artemis-model 0.1.89__tar.gz → 0.1.91__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {artemis_model-0.1.89 → artemis_model-0.1.91}/PKG-INFO +2 -1
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/album.py +4 -8
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/artist.py +1 -3
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/auth.py +6 -12
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/base.py +14 -6
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/dj_set.py +7 -15
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/genre.py +2 -7
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/location.py +3 -9
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/message.py +12 -3
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/organization.py +2 -6
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/otp.py +2 -7
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/permission.py +7 -13
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/playlist.py +10 -28
- artemis_model-0.1.91/artemis_model/redis/__init__.py +6 -0
- artemis_model-0.1.91/artemis_model/redis/device.py +22 -0
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/redis/zone_state.py +2 -6
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/setting.py +20 -19
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/track.py +6 -18
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/user.py +4 -12
- {artemis_model-0.1.89 → artemis_model-0.1.91}/pyproject.toml +2 -1
- artemis_model-0.1.89/artemis_model/redis/__init__.py +0 -5
- {artemis_model-0.1.89 → artemis_model-0.1.91}/README.md +0 -0
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/__init__.py +0 -0
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/category.py +0 -0
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/schedule.py +0 -0
- {artemis_model-0.1.89 → artemis_model-0.1.91}/artemis_model/zone.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: artemis-model
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.91
|
4
4
|
Summary:
|
5
5
|
Author: Jukeboxy
|
6
6
|
Requires-Python: >=3.10.6,<4.0.0
|
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
11
11
|
Requires-Dist: alembic (>=1.13.1,<2.0.0)
|
12
12
|
Requires-Dist: asyncpg (>=0.29.0,<0.30.0)
|
13
13
|
Requires-Dist: greenlet (>=3.0.2,<4.0.0)
|
14
|
+
Requires-Dist: pydantic (>=2.10.2,<3.0.0)
|
14
15
|
Requires-Dist: python-slugify (>=8.0.4,<9.0.0)
|
15
16
|
Requires-Dist: sqlalchemy (>=2.0.23,<3.0.0)
|
16
17
|
Description-Content-Type: text/markdown
|
@@ -19,9 +19,7 @@ class AlbumMixin(TimeStampMixin):
|
|
19
19
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
20
20
|
name: Mapped[str] = mapped_column(nullable=False)
|
21
21
|
description: Mapped[str | None] = mapped_column(nullable=True)
|
22
|
-
entry_date: Mapped[datetime] = mapped_column(
|
23
|
-
nullable=False, default=datetime.utcnow
|
24
|
-
)
|
22
|
+
entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
|
25
23
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
26
24
|
legacy_id: Mapped[str] = mapped_column(nullable=False)
|
27
25
|
is_internal: Mapped[bool] = mapped_column(nullable=False, default=False)
|
@@ -45,7 +43,7 @@ class AlbumMixin(TimeStampMixin):
|
|
45
43
|
"Track",
|
46
44
|
back_populates="album",
|
47
45
|
cascade="all, delete-orphan",
|
48
|
-
|
46
|
+
)
|
49
47
|
|
50
48
|
|
51
49
|
class AlbumSync(CustomSyncBase, AlbumMixin):
|
@@ -56,10 +54,8 @@ class Album(CustomBase, AlbumMixin):
|
|
56
54
|
pass
|
57
55
|
|
58
56
|
|
59
|
-
class AlbumArtistAssocMixin
|
60
|
-
album_id: Mapped[int] = mapped_column(
|
61
|
-
ForeignKey("album.id"), primary_key=True, nullable=False
|
62
|
-
)
|
57
|
+
class AlbumArtistAssocMixin:
|
58
|
+
album_id: Mapped[int] = mapped_column(ForeignKey("album.id"), primary_key=True, nullable=False)
|
63
59
|
artist_id: Mapped[int] = mapped_column(
|
64
60
|
ForeignKey("artist.id"), primary_key=True, nullable=False
|
65
61
|
)
|
@@ -18,9 +18,7 @@ def to_tsvector_ix(*columns):
|
|
18
18
|
class ArtistMixin(TimeStampMixin):
|
19
19
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
20
20
|
name: Mapped[str] = mapped_column(nullable=False)
|
21
|
-
entry_date: Mapped[datetime] = mapped_column(
|
22
|
-
nullable=False, default=datetime.utcnow
|
23
|
-
)
|
21
|
+
entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
|
24
22
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
25
23
|
is_internal: Mapped[bool] = mapped_column(nullable=False, default=False)
|
26
24
|
legacy_id: Mapped[str] = mapped_column(nullable=False)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Auth models."""
|
2
|
+
|
2
3
|
import uuid
|
3
4
|
from datetime import datetime
|
4
5
|
from typing import Optional
|
@@ -16,9 +17,7 @@ class UserUnverifiedAccountMixin(TimeStampMixin):
|
|
16
17
|
been verified. Once the user has been verified, the account will be moved to the UserAccount table.
|
17
18
|
"""
|
18
19
|
|
19
|
-
id: Mapped[uuid.UUID] = mapped_column(
|
20
|
-
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
21
|
-
)
|
20
|
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
22
21
|
email: Mapped[str] = mapped_column(index=True)
|
23
22
|
name: Mapped[str] = mapped_column(nullable=False)
|
24
23
|
mobile: Mapped[str] = mapped_column(nullable=True, index=True)
|
@@ -43,14 +42,10 @@ class UserAccountMixin(TimeStampMixin):
|
|
43
42
|
This table is used to store the account info of users who have been verified.
|
44
43
|
"""
|
45
44
|
|
46
|
-
id: Mapped[uuid.UUID] = mapped_column(
|
47
|
-
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
48
|
-
)
|
45
|
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
49
46
|
email: Mapped[str] = mapped_column(index=True, unique=True)
|
50
47
|
name: Mapped[str] = mapped_column(nullable=False)
|
51
|
-
mobile: Mapped[Optional[str]] = mapped_column(
|
52
|
-
nullable=True, unique=True, index=True
|
53
|
-
)
|
48
|
+
mobile: Mapped[Optional[str]] = mapped_column(nullable=True, unique=True, index=True)
|
54
49
|
password = mapped_column(LargeBinary, nullable=True)
|
55
50
|
provider: Mapped[str] = mapped_column(nullable=False)
|
56
51
|
oauth_id: Mapped[Optional[str]] = mapped_column(nullable=True, index=True)
|
@@ -84,9 +79,8 @@ class LoginHistoryMixin:
|
|
84
79
|
"""
|
85
80
|
This table is used to store the login history of users.
|
86
81
|
"""
|
87
|
-
|
88
|
-
|
89
|
-
)
|
82
|
+
|
83
|
+
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, nullable=False)
|
90
84
|
account_id: Mapped[uuid.UUID] = mapped_column(
|
91
85
|
ForeignKey("user_account.id"), nullable=False, index=True
|
92
86
|
)
|
@@ -2,8 +2,14 @@ import re
|
|
2
2
|
from datetime import datetime
|
3
3
|
from typing import Any
|
4
4
|
|
5
|
-
from sqlalchemy.orm import (
|
6
|
-
|
5
|
+
from sqlalchemy.orm import (
|
6
|
+
DeclarativeBase,
|
7
|
+
Mapped,
|
8
|
+
declared_attr,
|
9
|
+
mapped_column,
|
10
|
+
object_session,
|
11
|
+
relationship,
|
12
|
+
)
|
7
13
|
from sqlalchemy.ext.asyncio import AsyncAttrs
|
8
14
|
from sqlalchemy import Column, Uuid, event, inspect, TypeDecorator
|
9
15
|
from sqlalchemy.dialects.postgresql import TSVECTOR
|
@@ -45,8 +51,9 @@ class CustomBase(DeclarativeBase, AsyncAttrs):
|
|
45
51
|
for key in self.__repr_attrs__:
|
46
52
|
if not hasattr(self, key):
|
47
53
|
raise KeyError(
|
48
|
-
"{} has incorrect attribute '{}' in "
|
49
|
-
|
54
|
+
"{} has incorrect attribute '{}' in " "__repr__attrs__".format(
|
55
|
+
self.__class__, key
|
56
|
+
)
|
50
57
|
)
|
51
58
|
value = getattr(self, key)
|
52
59
|
wrap_in_quote = isinstance(value, str)
|
@@ -191,8 +198,9 @@ class CustomSyncBase(DeclarativeBase):
|
|
191
198
|
for key in self.__repr_attrs__:
|
192
199
|
if not hasattr(self, key):
|
193
200
|
raise KeyError(
|
194
|
-
"{} has incorrect attribute '{}' in "
|
195
|
-
|
201
|
+
"{} has incorrect attribute '{}' in " "__repr__attrs__".format(
|
202
|
+
self.__class__, key
|
203
|
+
)
|
196
204
|
)
|
197
205
|
value = getattr(self, key)
|
198
206
|
wrap_in_quote = isinstance(value, str)
|
@@ -37,9 +37,7 @@ class DjSetMixin(TimeStampMixin, AuditMixin):
|
|
37
37
|
organization_id: Mapped[uuid.UUID] = mapped_column(
|
38
38
|
ForeignKey("organization.id"), nullable=True, index=True
|
39
39
|
)
|
40
|
-
entry_date: Mapped[datetime] = mapped_column(
|
41
|
-
nullable=False, default=datetime.utcnow
|
42
|
-
)
|
40
|
+
entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
|
43
41
|
cover_image: Mapped[str] = mapped_column(nullable=True)
|
44
42
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
45
43
|
legacy_id: Mapped[str] = mapped_column(nullable=True)
|
@@ -62,7 +60,9 @@ class DjSetMixin(TimeStampMixin, AuditMixin):
|
|
62
60
|
return association_proxy(
|
63
61
|
"dj_set_genre_associations",
|
64
62
|
"genre",
|
65
|
-
creator=lambda genre: DjSetGenreAssoc(
|
63
|
+
creator=lambda genre: DjSetGenreAssoc(
|
64
|
+
genre_id=genre.get("id"), weight=genre.get("weight", 0)
|
65
|
+
),
|
66
66
|
)
|
67
67
|
|
68
68
|
@declared_attr
|
@@ -71,24 +71,16 @@ class DjSetMixin(TimeStampMixin, AuditMixin):
|
|
71
71
|
|
72
72
|
@declared_attr
|
73
73
|
def dj_set_track_associations(cls) -> Mapped[list["DjSetTrackAssoc"]]:
|
74
|
-
return relationship(
|
75
|
-
cascade="all, delete-orphan"
|
76
|
-
)
|
74
|
+
return relationship(cascade="all, delete-orphan")
|
77
75
|
|
78
76
|
@declared_attr
|
79
77
|
def genres(cls) -> Mapped[list["Genre"]]:
|
80
|
-
return relationship(
|
81
|
-
secondary="dj_set_genre_assoc",
|
82
|
-
lazy="joined",
|
83
|
-
viewonly=True
|
84
|
-
)
|
78
|
+
return relationship(secondary="dj_set_genre_assoc", lazy="joined", viewonly=True)
|
85
79
|
|
86
80
|
|
87
81
|
@declared_attr
|
88
82
|
def tracks(cls) -> Mapped[list["Track"]]:
|
89
|
-
return relationship(
|
90
|
-
secondary="dj_set_track_assoc", viewonly=True
|
91
|
-
)
|
83
|
+
return relationship(secondary="dj_set_track_assoc", viewonly=True)
|
92
84
|
|
93
85
|
|
94
86
|
class DjSetSync(CustomSyncBase, DjSetMixin):
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
from sqlalchemy import Computed, func, literal, text
|
3
2
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
4
3
|
|
@@ -26,15 +25,11 @@ class GenreMixin(TimeStampMixin):
|
|
26
25
|
|
27
26
|
@declared_attr
|
28
27
|
def tracks(cls) -> Mapped[list["Track"]]:
|
29
|
-
return relationship(
|
30
|
-
"Track", secondary="track_genre_assoc", back_populates="genres"
|
31
|
-
)
|
28
|
+
return relationship("Track", secondary="track_genre_assoc", back_populates="genres")
|
32
29
|
|
33
30
|
@declared_attr
|
34
31
|
def dj_set_genre_associations(cls) -> Mapped[list["DjSetGenreAssoc"]]:
|
35
|
-
return relationship(
|
36
|
-
back_populates="genre", cascade="all, delete-orphan"
|
37
|
-
)
|
32
|
+
return relationship(back_populates="genre", cascade="all, delete-orphan")
|
38
33
|
|
39
34
|
def dj_sets(cls) -> Mapped[list["DjSet"]]:
|
40
35
|
return relationship("DjSet", secondary="dj_set_genre_assoc", back_populates="genre")
|
@@ -38,9 +38,7 @@ class Address(CustomBase, AddressMixin):
|
|
38
38
|
|
39
39
|
|
40
40
|
class LocationMixin(TimeStampMixin):
|
41
|
-
id: Mapped[uuid.UUID] = mapped_column(
|
42
|
-
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
43
|
-
)
|
41
|
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
44
42
|
name: Mapped[str] = mapped_column(nullable=False)
|
45
43
|
slug: Mapped[str] = mapped_column(nullable=False)
|
46
44
|
organization_id: Mapped[uuid.UUID] = mapped_column(
|
@@ -113,9 +111,7 @@ listen(Location.name, "set", generate_slug)
|
|
113
111
|
|
114
112
|
class LocationGroupMixin(TimeStampMixin):
|
115
113
|
id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True)
|
116
|
-
organization_id = mapped_column(
|
117
|
-
ForeignKey("organization.id"), nullable=False, index=True
|
118
|
-
)
|
114
|
+
organization_id = mapped_column(ForeignKey("organization.id"), nullable=False, index=True)
|
119
115
|
name: Mapped[str] = mapped_column(nullable=False)
|
120
116
|
description: Mapped[str] = mapped_column(nullable=True)
|
121
117
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
@@ -136,9 +132,7 @@ class LocationGroup(CustomBase, LocationGroupMixin):
|
|
136
132
|
|
137
133
|
|
138
134
|
class UserLocationAssocMixin(TimeStampMixin):
|
139
|
-
location_id: Mapped[uuid.UUID] = mapped_column(
|
140
|
-
ForeignKey("location.id"), primary_key=True
|
141
|
-
)
|
135
|
+
location_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("location.id"), primary_key=True)
|
142
136
|
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("user.id"), primary_key=True)
|
143
137
|
|
144
138
|
@declared_attr
|
@@ -12,13 +12,18 @@ class MessageMixin(TimeStampMixin, AuditMixin):
|
|
12
12
|
"""
|
13
13
|
This table is used to store the message.
|
14
14
|
"""
|
15
|
+
|
15
16
|
id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True, index=True)
|
16
17
|
name: Mapped[str] = mapped_column(nullable=False)
|
17
18
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
18
19
|
s3_link: Mapped[str] = mapped_column(nullable=False)
|
19
20
|
|
20
|
-
organization_id: Mapped[uuid.UUID] = mapped_column(
|
21
|
-
|
21
|
+
organization_id: Mapped[uuid.UUID] = mapped_column(
|
22
|
+
ForeignKey("organization.id"), nullable=False, index=True
|
23
|
+
)
|
24
|
+
message_group_id: Mapped[int] = mapped_column(
|
25
|
+
ForeignKey("message_group.id"), nullable=True, index=True, default=None
|
26
|
+
)
|
22
27
|
|
23
28
|
@declared_attr
|
24
29
|
def organization(cls) -> Mapped["Organization"]:
|
@@ -47,6 +52,7 @@ class MessagePlayDetailMixin(TimeStampMixin, AuditMixin):
|
|
47
52
|
Frequency is used only for rotated messages.
|
48
53
|
Timesheet is used only for scheduled messages.
|
49
54
|
"""
|
55
|
+
|
50
56
|
id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True, index=True)
|
51
57
|
message_id: Mapped[int] = mapped_column(ForeignKey("message.id"), nullable=False, index=True)
|
52
58
|
zone_id: Mapped[int] = mapped_column(ForeignKey("zone.id"), index=True)
|
@@ -76,9 +82,12 @@ class MessageGroupMixin(TimeStampMixin, AuditMixin):
|
|
76
82
|
"""
|
77
83
|
This table is used to store the message group.
|
78
84
|
"""
|
85
|
+
|
79
86
|
id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True, index=True)
|
80
87
|
name: Mapped[str] = mapped_column(nullable=False)
|
81
|
-
organization_id: Mapped[uuid.UUID] = mapped_column(
|
88
|
+
organization_id: Mapped[uuid.UUID] = mapped_column(
|
89
|
+
ForeignKey("organization.id"), nullable=False, index=True
|
90
|
+
)
|
82
91
|
|
83
92
|
@declared_attr
|
84
93
|
def organization(cls) -> Mapped["Organization"]:
|
@@ -12,9 +12,7 @@ from sqlalchemy.ext.declarative import declared_attr
|
|
12
12
|
|
13
13
|
|
14
14
|
class OrganizationMixin(TimeStampMixin):
|
15
|
-
id: Mapped[uuid.UUID] = mapped_column(
|
16
|
-
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
17
|
-
)
|
15
|
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
18
16
|
name: Mapped[str] = mapped_column(nullable=False)
|
19
17
|
description: Mapped[str | None] = mapped_column(nullable=True)
|
20
18
|
slug: Mapped[str] = mapped_column(nullable=False, index=True)
|
@@ -30,9 +28,7 @@ class OrganizationMixin(TimeStampMixin):
|
|
30
28
|
|
31
29
|
@declared_attr
|
32
30
|
def users(cls) -> Mapped[List["User"]]:
|
33
|
-
return relationship(
|
34
|
-
secondary="organization_user_assoc", back_populates="organizations"
|
35
|
-
)
|
31
|
+
return relationship(secondary="organization_user_assoc", back_populates="organizations")
|
36
32
|
|
37
33
|
@declared_attr
|
38
34
|
def messages(cls) -> Mapped[List["Message"]]:
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
import uuid
|
3
2
|
from datetime import datetime
|
4
3
|
from sqlalchemy.orm import Mapped, mapped_column
|
@@ -12,18 +11,14 @@ class OtpMixin(TimeStampMixin):
|
|
12
11
|
requested_by can be an UserAccount or UserUnverifiedAccount id.
|
13
12
|
"""
|
14
13
|
|
15
|
-
id: Mapped[int] = mapped_column(
|
16
|
-
primary_key=True, autoincrement=True, nullable=False
|
17
|
-
)
|
14
|
+
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, nullable=False)
|
18
15
|
code: Mapped[str] = mapped_column(nullable=False)
|
19
16
|
purpose: Mapped[str] = mapped_column(nullable=False)
|
20
17
|
requested_by_id: Mapped[uuid.UUID] = mapped_column(nullable=False, index=True)
|
21
18
|
method: Mapped[str] = mapped_column(nullable=False, index=True)
|
22
19
|
secret: Mapped[str] = mapped_column(nullable=False)
|
23
20
|
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow, index=True)
|
24
|
-
updated_at: Mapped[datetime] = mapped_column(
|
25
|
-
default=datetime.utcnow, onupdate=datetime.utcnow
|
26
|
-
)
|
21
|
+
updated_at: Mapped[datetime] = mapped_column(default=datetime.utcnow, onupdate=datetime.utcnow)
|
27
22
|
|
28
23
|
|
29
24
|
class OtpSync(CustomSyncBase, OtpMixin):
|
@@ -10,27 +10,21 @@ from sqlalchemy.ext.declarative import declared_attr
|
|
10
10
|
|
11
11
|
|
12
12
|
class PermissionMixin(TimeStampMixin):
|
13
|
-
id: Mapped[str] = mapped_column(
|
14
|
-
primary_key=True
|
15
|
-
)
|
13
|
+
id: Mapped[str] = mapped_column(primary_key=True)
|
16
14
|
name: Mapped[str] = mapped_column(nullable=False)
|
17
15
|
description: Mapped[str] = mapped_column(nullable=False)
|
18
|
-
type: Mapped[str] = mapped_column(
|
16
|
+
type: Mapped[str] = mapped_column(
|
17
|
+
nullable=False
|
18
|
+
) # music-management, player-management, user-management
|
19
19
|
|
20
20
|
@declared_attr
|
21
21
|
def user_permission_associations(cls) -> Mapped[List["UserPermissionAssoc"]]:
|
22
|
-
return relationship(
|
23
|
-
back_populates="permission", cascade="all, delete-orphan"
|
24
|
-
)
|
22
|
+
return relationship(back_populates="permission", cascade="all, delete-orphan")
|
25
23
|
|
26
24
|
|
27
25
|
class UserPermissionAssocMixin(TimeStampMixin):
|
28
|
-
user_id: Mapped[uuid.UUID] = mapped_column(
|
29
|
-
|
30
|
-
)
|
31
|
-
permission_id: Mapped[uuid.UUID] = mapped_column(
|
32
|
-
ForeignKey("permission.id"), primary_key=True
|
33
|
-
)
|
26
|
+
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("user.id"), primary_key=True)
|
27
|
+
permission_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("permission.id"), primary_key=True)
|
34
28
|
|
35
29
|
@declared_attr
|
36
30
|
def permission(cls) -> Mapped["Permission"]:
|
@@ -16,9 +16,7 @@ def to_tsvector_ix(*columns):
|
|
16
16
|
|
17
17
|
|
18
18
|
class FavoritePlaylistMixin:
|
19
|
-
playlist_id: Mapped[int] = mapped_column(
|
20
|
-
ForeignKey("playlist.id"), primary_key=True
|
21
|
-
)
|
19
|
+
playlist_id: Mapped[int] = mapped_column(ForeignKey("playlist.id"), primary_key=True)
|
22
20
|
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("user.id"), primary_key=True)
|
23
21
|
|
24
22
|
|
@@ -33,9 +31,7 @@ class FavoritePlaylist(CustomBase, FavoritePlaylistMixin):
|
|
33
31
|
class PlaylistMixin(TimeStampMixin):
|
34
32
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
35
33
|
name: Mapped[str] = mapped_column(nullable=False, unique=True)
|
36
|
-
entry_date: Mapped[datetime] = mapped_column(
|
37
|
-
nullable=False, default=datetime.utcnow
|
38
|
-
)
|
34
|
+
entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
|
39
35
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
40
36
|
legacy_id: Mapped[str] = mapped_column(nullable=True)
|
41
37
|
is_published: Mapped[bool] = mapped_column(default=False) # legacy isTest
|
@@ -59,7 +55,7 @@ class PlaylistMixin(TimeStampMixin):
|
|
59
55
|
"FavoritePlaylist",
|
60
56
|
primaryjoin="and_(FavoritePlaylist.playlist_id == Playlist.id)",
|
61
57
|
viewonly=True,
|
62
|
-
lazy="select"
|
58
|
+
lazy="select",
|
63
59
|
)
|
64
60
|
|
65
61
|
@hybrid_property
|
@@ -67,21 +63,15 @@ class PlaylistMixin(TimeStampMixin):
|
|
67
63
|
return bool(self.favorite_playlist_associations)
|
68
64
|
|
69
65
|
@declared_attr
|
70
|
-
def category_playlist_associations(cls) -> Mapped[
|
71
|
-
list["PlaylistCategoryAssoc"]
|
72
|
-
]:
|
66
|
+
def category_playlist_associations(cls) -> Mapped[list["PlaylistCategoryAssoc"]]:
|
73
67
|
return relationship(cascade="all, delete-orphan")
|
74
68
|
|
75
69
|
@declared_attr
|
76
70
|
def track_playlist_associations(cls) -> Mapped[list["PlaylistTrackAssoc"]]:
|
77
|
-
return relationship(
|
78
|
-
cascade="all, delete-orphan"
|
79
|
-
)
|
71
|
+
return relationship(cascade="all, delete-orphan")
|
80
72
|
|
81
73
|
@declared_attr
|
82
|
-
def organization_playlist_associations(cls) -> Mapped[
|
83
|
-
list["PlaylistOrganizationAssoc"]
|
84
|
-
]:
|
74
|
+
def organization_playlist_associations(cls) -> Mapped[list["PlaylistOrganizationAssoc"]]:
|
85
75
|
return relationship(cascade="all, delete-orphan")
|
86
76
|
|
87
77
|
@declared_attr
|
@@ -110,15 +100,11 @@ class PlaylistMixin(TimeStampMixin):
|
|
110
100
|
|
111
101
|
@declared_attr
|
112
102
|
def tracks(cls) -> Mapped[list["Track"]]:
|
113
|
-
return relationship(
|
114
|
-
secondary="playlist_track_assoc", viewonly=True
|
115
|
-
)
|
103
|
+
return relationship(secondary="playlist_track_assoc", viewonly=True)
|
116
104
|
|
117
105
|
@declared_attr
|
118
106
|
def categories(cls) -> Mapped[list["Category"]]:
|
119
|
-
return relationship(
|
120
|
-
secondary="playlist_category_assoc", viewonly=True
|
121
|
-
)
|
107
|
+
return relationship(secondary="playlist_category_assoc", viewonly=True)
|
122
108
|
|
123
109
|
# __table_args__ = (
|
124
110
|
# Index(
|
@@ -176,18 +162,14 @@ class PlaylistTrackAssoc(CustomBase, PlaylistTrackAssocMixin):
|
|
176
162
|
|
177
163
|
|
178
164
|
class PlaylistCategoryAssocMixin(TimeStampMixin):
|
179
|
-
playlist_id = mapped_column(
|
180
|
-
ForeignKey("playlist.id"), primary_key=True, nullable=False
|
181
|
-
)
|
165
|
+
playlist_id = mapped_column(ForeignKey("playlist.id"), primary_key=True, nullable=False)
|
182
166
|
category_id: Mapped[int] = mapped_column(
|
183
167
|
ForeignKey("category.id"), primary_key=True, nullable=False
|
184
168
|
)
|
185
169
|
|
186
170
|
@declared_attr
|
187
171
|
def category(cls) -> Mapped["Category"]:
|
188
|
-
return relationship(
|
189
|
-
back_populates="category_playlist_associations"
|
190
|
-
)
|
172
|
+
return relationship(back_populates="category_playlist_associations")
|
191
173
|
|
192
174
|
|
193
175
|
class PlaylistCategoryAssocSync(CustomSyncBase, PlaylistCategoryAssocMixin):
|
@@ -0,0 +1,22 @@
|
|
1
|
+
"""Active device redis model."""
|
2
|
+
|
3
|
+
from datetime import datetime, timezone
|
4
|
+
from typing import Literal
|
5
|
+
from uuid import UUID
|
6
|
+
|
7
|
+
from pydantic import BaseModel, Field
|
8
|
+
|
9
|
+
|
10
|
+
class ActiveDevice(BaseModel):
|
11
|
+
"""Active device schema."""
|
12
|
+
|
13
|
+
user_id: UUID
|
14
|
+
client_id: str
|
15
|
+
device_id: str
|
16
|
+
mode: Literal["player-mode", "controller-mode"]
|
17
|
+
connected_at: datetime | str = Field(
|
18
|
+
default_factory=lambda: datetime.now(timezone.utc).isoformat()
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
__all__ = ["ActiveDevice"]
|
@@ -1,10 +1,8 @@
|
|
1
1
|
"""Zone state schema."""
|
2
2
|
|
3
|
-
|
4
|
-
from dataclasses import Field
|
5
3
|
from typing import Annotated, Literal
|
6
4
|
|
7
|
-
from pydantic import BaseModel, field_validator
|
5
|
+
from pydantic import BaseModel, Field, field_validator
|
8
6
|
|
9
7
|
|
10
8
|
class NowPlaying(BaseModel):
|
@@ -29,7 +27,6 @@ BucketId = Annotated[
|
|
29
27
|
]
|
30
28
|
|
31
29
|
|
32
|
-
|
33
30
|
class ZoneState(BaseModel):
|
34
31
|
"""Zone state schema."""
|
35
32
|
|
@@ -55,7 +52,6 @@ class ZoneState(BaseModel):
|
|
55
52
|
def default_empty_dict_if_none(cls, v):
|
56
53
|
"""Override none value to empty dict."""
|
57
54
|
return v or {}
|
58
|
-
|
59
|
-
|
55
|
+
|
60
56
|
|
61
57
|
__all__ = ["ZoneState", "NowPlaying", "SessionId", "BucketId"]
|
@@ -8,26 +8,27 @@ from sqlalchemy.ext.declarative import declared_attr
|
|
8
8
|
|
9
9
|
class SettingMixin(TimeStampMixin):
|
10
10
|
"""
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
11
|
+
Exclusion Schema
|
12
|
+
{
|
13
|
+
"genres": {
|
14
|
+
"<genre_id>": "<genre_name>",
|
15
|
+
"<genre_id>": "<genre_name>",
|
16
|
+
...
|
17
|
+
},
|
18
|
+
"artists": {
|
19
|
+
"<artist_id>": "<artist_name>",
|
20
|
+
"<artist_id>": "<artist_name>",
|
21
|
+
...
|
22
|
+
},
|
23
|
+
"tracks": {
|
24
|
+
"<track_id>": "<track_name>",
|
25
|
+
"<track_id>": "<track_name>",
|
26
|
+
...
|
27
|
+
},
|
28
|
+
"exclude_pal": True/False
|
29
|
+
}
|
30
30
|
"""
|
31
|
+
|
31
32
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
32
33
|
zone_id: Mapped[int] = mapped_column(ForeignKey("zone.id"), index=True)
|
33
34
|
exclusion: Mapped[JSON] = mapped_column(JSON, nullable=True)
|
@@ -16,17 +16,11 @@ def to_tsvector_ix(*columns):
|
|
16
16
|
|
17
17
|
|
18
18
|
class TrackMixin(TimeStampMixin):
|
19
|
-
id: Mapped[uuid.UUID] = mapped_column(
|
20
|
-
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
21
|
-
)
|
19
|
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
22
20
|
name: Mapped[str] = mapped_column(nullable=False)
|
23
21
|
album_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("album.id"), nullable=False)
|
24
|
-
artist_id: Mapped[uuid.UUID] = mapped_column(
|
25
|
-
|
26
|
-
)
|
27
|
-
entry_date: Mapped[datetime] = mapped_column(
|
28
|
-
nullable=False, default=datetime.utcnow
|
29
|
-
)
|
22
|
+
artist_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("artist.id"), nullable=False)
|
23
|
+
entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
|
30
24
|
disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
|
31
25
|
legacy_id: Mapped[str] = mapped_column(nullable=False)
|
32
26
|
is_internal: Mapped[bool] = mapped_column(nullable=False, default=False)
|
@@ -42,15 +36,11 @@ class TrackMixin(TimeStampMixin):
|
|
42
36
|
|
43
37
|
@declared_attr
|
44
38
|
def track_playlist_associations(cls) -> Mapped[list["PlaylistTrackAssoc"]]:
|
45
|
-
return relationship(
|
46
|
-
back_populates="track", cascade="all, delete-orphan"
|
47
|
-
)
|
39
|
+
return relationship(back_populates="track", cascade="all, delete-orphan")
|
48
40
|
|
49
41
|
@declared_attr
|
50
42
|
def dj_set_track_associations(cls) -> Mapped[list["DjSetTrackAssoc"]]:
|
51
|
-
return relationship(
|
52
|
-
back_populates="track", cascade="all, delete-orphan"
|
53
|
-
)
|
43
|
+
return relationship(back_populates="track", cascade="all, delete-orphan")
|
54
44
|
|
55
45
|
@declared_attr
|
56
46
|
def album(cls) -> Mapped["Album"]:
|
@@ -62,9 +52,7 @@ class TrackMixin(TimeStampMixin):
|
|
62
52
|
|
63
53
|
@declared_attr
|
64
54
|
def genres(cls) -> Mapped[List["Genre"]]:
|
65
|
-
return relationship(
|
66
|
-
"Genre", secondary="track_genre_assoc", back_populates="tracks"
|
67
|
-
)
|
55
|
+
return relationship("Genre", secondary="track_genre_assoc", back_populates="tracks")
|
68
56
|
|
69
57
|
@declared_attr
|
70
58
|
def label(cls) -> Mapped["TrackLabel"]:
|
@@ -14,9 +14,7 @@ class UserMixin(TimeStampMixin):
|
|
14
14
|
This table is used to store the user itself.
|
15
15
|
"""
|
16
16
|
|
17
|
-
id: Mapped[uuid.UUID] = mapped_column(
|
18
|
-
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
19
|
-
)
|
17
|
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
20
18
|
account_id: Mapped[uuid.UUID] = mapped_column(
|
21
19
|
ForeignKey("user_account.id"), nullable=False, index=True
|
22
20
|
)
|
@@ -40,15 +38,11 @@ class UserMixin(TimeStampMixin):
|
|
40
38
|
|
41
39
|
@declared_attr
|
42
40
|
def organizations(cls) -> Mapped[List["Organization"]]:
|
43
|
-
return relationship(
|
44
|
-
secondary="organization_user_assoc", back_populates="users"
|
45
|
-
)
|
41
|
+
return relationship(secondary="organization_user_assoc", back_populates="users")
|
46
42
|
|
47
43
|
@declared_attr
|
48
44
|
def locations(cls) -> Mapped[List["Location"]]:
|
49
|
-
return relationship(
|
50
|
-
secondary="user_location_assoc", viewonly=True
|
51
|
-
)
|
45
|
+
return relationship(secondary="user_location_assoc", viewonly=True)
|
52
46
|
|
53
47
|
@declared_attr
|
54
48
|
def permission_ids(cls) -> AssociationProxy[List["Permission"] | None]:
|
@@ -60,9 +54,7 @@ class UserMixin(TimeStampMixin):
|
|
60
54
|
|
61
55
|
@declared_attr
|
62
56
|
def permissions(cls) -> Mapped[list["Permission"]]:
|
63
|
-
return relationship(
|
64
|
-
secondary="user_permission_assoc", viewonly=True
|
65
|
-
)
|
57
|
+
return relationship(secondary="user_permission_assoc", viewonly=True)
|
66
58
|
|
67
59
|
|
68
60
|
class UserSync(CustomSyncBase, UserMixin):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "artemis-model"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.91"
|
4
4
|
description = ""
|
5
5
|
authors = ["Jukeboxy"]
|
6
6
|
readme = "README.md"
|
@@ -12,6 +12,7 @@ greenlet = "^3.0.2"
|
|
12
12
|
python-slugify = "^8.0.4"
|
13
13
|
alembic = "^1.13.1"
|
14
14
|
asyncpg = "^0.29.0"
|
15
|
+
pydantic = "^2.10.2"
|
15
16
|
|
16
17
|
|
17
18
|
[tool.poetry.dev-dependencies]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|