Coverage for app/models.py: 100%

106 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2026-03-24 11:40 +0000

1import uuid 

2from datetime import datetime 

3 

4from pydantic import EmailStr 

5from sqlalchemy import JSON, Column 

6from sqlmodel import Field, Relationship, SQLModel 

7 

8 

9# Shared properties 

10class UserBase(SQLModel): 

11 email: EmailStr = Field(unique=True, index=True, max_length=255) 

12 is_active: bool = True 

13 is_superuser: bool = False 

14 full_name: str | None = Field(default=None, max_length=255) 

15 

16 

17# Properties to receive via API on creation 

18class UserCreate(UserBase): 

19 password: str = Field(min_length=8, max_length=40) 

20 

21 

22class UserRegister(SQLModel): 

23 email: EmailStr = Field(max_length=255) 

24 password: str = Field(min_length=8, max_length=40) 

25 full_name: str | None = Field(default=None, max_length=255) 

26 

27 

28# Properties to receive via API on update, all are optional 

29class UserUpdate(UserBase): 

30 email: EmailStr | None = Field(default=None, max_length=255) # type: ignore 

31 password: str | None = Field(default=None, min_length=8, max_length=40) 

32 work_start: int | None = Field(default=None) 

33 work_end: int | None = Field(default=None) 

34 

35 

36class UserUpdateMe(SQLModel): 

37 full_name: str | None = Field(default=None, max_length=255) 

38 email: EmailStr | None = Field(default=None, max_length=255) 

39 work_start: int | None = Field(default=None) 

40 work_end: int | None = Field(default=None) 

41 

42 

43class UpdatePassword(SQLModel): 

44 current_password: str = Field(min_length=8, max_length=40) 

45 new_password: str = Field(min_length=8, max_length=40) 

46 

47 

48# Database model, database table inferred from class name 

49class User(UserBase, table=True): 

50 id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) 

51 hashed_password: str 

52 work_start: int = Field(default=9) 

53 work_end: int = Field(default=18) 

54 items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True) 

55 tasks: list["Task"] = Relationship(back_populates="owner", cascade_delete=True) 

56 

57 

58# Properties to return via API, id is always required 

59class UserPublic(UserBase): 

60 id: uuid.UUID 

61 work_start: int = Field(default=9) 

62 work_end: int = Field(default=18) 

63 

64 

65class UsersPublic(SQLModel): 

66 data: list[UserPublic] 

67 count: int 

68 

69 

70# Shared properties 

71class ItemBase(SQLModel): 

72 title: str = Field(min_length=1, max_length=255) 

73 description: str | None = Field(default=None, max_length=255) 

74 

75 

76# Properties to receive on item creation 

77class ItemCreate(ItemBase): 

78 pass 

79 

80 

81# Properties to receive on item update 

82class ItemUpdate(ItemBase): 

83 title: str | None = Field(default=None, min_length=1, max_length=255) # type: ignore 

84 

85 

86# Database model, database table inferred from class name 

87class Item(ItemBase, table=True): 

88 id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) 

89 title: str = Field(max_length=255) 

90 owner_id: uuid.UUID = Field( 

91 foreign_key="user.id", nullable=False, ondelete="CASCADE" 

92 ) 

93 owner: User | None = Relationship(back_populates="items") 

94 

95 

96# Properties to return via API, id is always required 

97class ItemPublic(ItemBase): 

98 id: uuid.UUID 

99 owner_id: uuid.UUID 

100 

101 

102class ItemsPublic(SQLModel): 

103 data: list[ItemPublic] 

104 count: int 

105 

106 

107# Generic message 

108class Message(SQLModel): 

109 message: str 

110 

111 

112# JSON payload containing access token 

113class Token(SQLModel): 

114 access_token: str 

115 token_type: str = "bearer" 

116 

117 

118# Contents of JWT token 

119class TokenPayload(SQLModel): 

120 sub: str | None = None 

121 

122 

123class NewPassword(SQLModel): 

124 token: str 

125 new_password: str = Field(min_length=8, max_length=40) 

126 

127 

128class Priority(SQLModel, table=True): 

129 id: int | None = Field(default=None, primary_key=True) 

130 name: str | None = Field(default=None, max_length=255) 

131 value: int | None = Field(default=None) 

132 

133 

134class TaskBase(SQLModel): 

135 title: str | None = Field(default=None, max_length=255) 

136 description: str | None = Field(default=None, max_length=255) 

137 priority_id: int | None = Field( 

138 default=None, foreign_key="priority.id", nullable=True 

139 ) 

140 duration: int | None = Field(default=None) 

141 due: datetime | None = Field(default=None) 

142 scheduled_start: datetime | None = Field(default=None) 

143 completed: bool = Field(default=False) 

144 position: int | None = Field(default=None, index=True) 

145 tags: list[str] | None = Field(default=None, sa_column=Column(JSON)) 

146 

147 

148class TaskCreate(TaskBase): 

149 title: str = Field(min_length=1, max_length=255) 

150 

151 

152class TaskUpdate(SQLModel): 

153 title: str | None = Field(default=None, min_length=1, max_length=255) 

154 description: str | None = Field(default=None, max_length=255) 

155 priority_id: int | None = Field(default=None) 

156 duration: int | None = Field(default=None) 

157 due: datetime | None = Field(default=None) 

158 scheduled_start: datetime | None = Field(default=None) 

159 completed: bool | None = Field(default=None) 

160 tags: list[str] | None = Field(default=None) 

161 

162 

163class Task(TaskBase, table=True): 

164 id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) 

165 owner_id: uuid.UUID = Field( 

166 foreign_key="user.id", nullable=False, ondelete="CASCADE" 

167 ) 

168 owner: User | None = Relationship(back_populates="tasks") 

169 

170 

171class TaskPublic(TaskBase): 

172 id: uuid.UUID 

173 owner_id: uuid.UUID 

174 

175 

176class TasksPublic(SQLModel): 

177 data: list[TaskPublic] 

178 count: int