user_info.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import datetime
  2. from typing import Optional
  3. import os
  4. import sys
  5. sys.path.append(os.path.dirname(os.path.dirname(__file__)))
  6. from db.engine import engine
  7. from sqlmodel import Field, SQLModel,Relationship,create_engine,Session,select,func,Column
  8. import psycopg2
  9. from config import DB_URL,logger
  10. # from db.common import engine
  11. from sqlalchemy import UniqueConstraint, Index, asc
  12. from sqlalchemy.dialects.postgresql import insert
  13. from db.base import DouyinBaseRepository
  14. '''
  15. https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/account-management/get-account-open-info
  16. 理论上无需将用户信息存入数据库,因为抖音已经存储了这些信息,我本地再存储一份无疑造成数据冗余。
  17. 直接从抖音获取:
  18. - 可以获得很好的实时性。比如用户更新了头像,在我的网站应用中也能实时更新
  19. - 避免数据冗余,不增加无意义的代码量
  20. - 没有请求次数限制
  21. 存储在本地:
  22. - 我有大量的本地数据分析的需求
  23. - 避免延迟和其他网络问题,但通常抖音服务器不会有网络问题
  24. 综上,我认为不需要将用户信息存储在本地数据库。因为抖音并没有限制该接口请求次数。
  25. '''
  26. # 避免循环导入问题,参考 SQLmodel 官方: https://sqlmodel.tiangolo.com/tutorial/code-structure/
  27. from typing import TYPE_CHECKING, Optional
  28. if TYPE_CHECKING:
  29. from .user import User
  30. class UserInfoLink(SQLModel, table=True):
  31. user_id: Optional[int] = Field(
  32. default=None, foreign_key="user.id", primary_key=True
  33. )
  34. info_id: Optional[int] = Field(
  35. default=None, foreign_key="userinfo.id", primary_key=True
  36. )
  37. class UserInfo(SQLModel, table=True):
  38. id: Optional[int] = Field(default=None, primary_key=True)
  39. avatar: Optional[str] = Field(default=None)
  40. avatar_larger: Optional[str] = Field(default=None)
  41. client_key: Optional[str] = Field(default=None)
  42. e_account_role: Optional[str] = Field(default=None)
  43. nickname: Optional[str] = Field(default=None)
  44. # 外键约束有助于:级联操作、避免冗余、数据完整性
  45. open_id: Optional[str] = Field(index=True, unique=True)
  46. union_id: Optional[str] = Field(default=None)
  47. update_time: datetime.datetime = Field(default_factory=datetime.datetime.now) # 添加时间戳字段
  48. user:"User" = Relationship(back_populates="info", link_model=UserInfoLink, sa_relationship_kwargs={"cascade": "all, delete-orphan", "single_parent":True})
  49. class UserInfoRepository(DouyinBaseRepository):
  50. def __init__(self, engine=engine):
  51. super().__init__(UserInfo, engine)
  52. self.model:UserInfo
  53. async def main():
  54. from douyin.user_info import get_user_info
  55. from db.user_oauth import UserOAuthRepository
  56. db_oauth = UserOAuthRepository()
  57. oauth_model = db_oauth.get_by_open_id()
  58. data = await get_user_info(oauth_model.open_id, oauth_model.access_token)
  59. if data.get("error_code") != 0:
  60. raise HTTPException(status_code=400, detail=data)
  61. db_user = UserInfoRepository()
  62. user_info_model = db_user.dict_to_model(data)
  63. db_user.add_or_update(user_info_model)
  64. # 生成并返回 token,包含过期时间
  65. payload = {
  66. "sub": data["open_id"],
  67. "exp": exp # 添加过期时间戳(北京时间)到 payload
  68. }
  69. account_token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
  70. logger.info(f"login success, expires_time:{datetime.datetime.fromtimestamp(exp).strftime('%Y-%m-%d %H:%M:%S') }, token:{account_token}")
  71. if __name__ == "__main__":
  72. main()