artemis-model 0.1.178__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.

Potentially problematic release.


This version of artemis-model might be problematic. Click here for more details.

Files changed (36) hide show
  1. artemis_model-0.1.178/PKG-INFO +116 -0
  2. artemis_model-0.1.178/README.md +96 -0
  3. artemis_model-0.1.178/artemis_model/__init__.py +22 -0
  4. artemis_model-0.1.178/artemis_model/album.py +69 -0
  5. artemis_model-0.1.178/artemis_model/approved_playlist_list.py +55 -0
  6. artemis_model-0.1.178/artemis_model/artist.py +49 -0
  7. artemis_model-0.1.178/artemis_model/auth.py +184 -0
  8. artemis_model-0.1.178/artemis_model/banned_tracks.py +24 -0
  9. artemis_model-0.1.178/artemis_model/base.py +229 -0
  10. artemis_model-0.1.178/artemis_model/category.py +53 -0
  11. artemis_model-0.1.178/artemis_model/dj_set.py +112 -0
  12. artemis_model-0.1.178/artemis_model/genre.py +47 -0
  13. artemis_model-0.1.178/artemis_model/location.py +156 -0
  14. artemis_model-0.1.178/artemis_model/location_genre_exclusion.py +38 -0
  15. artemis_model-0.1.178/artemis_model/message.py +106 -0
  16. artemis_model-0.1.178/artemis_model/organization.py +95 -0
  17. artemis_model-0.1.178/artemis_model/organization_include_pal_setting.py +32 -0
  18. artemis_model-0.1.178/artemis_model/otp.py +29 -0
  19. artemis_model-0.1.178/artemis_model/permission.py +47 -0
  20. artemis_model-0.1.178/artemis_model/playlist.py +198 -0
  21. artemis_model-0.1.178/artemis_model/redis/__init__.py +40 -0
  22. artemis_model-0.1.178/artemis_model/redis/bucket.py +50 -0
  23. artemis_model-0.1.178/artemis_model/redis/device.py +22 -0
  24. artemis_model-0.1.178/artemis_model/redis/keys.py +18 -0
  25. artemis_model-0.1.178/artemis_model/redis/play_history.py +44 -0
  26. artemis_model-0.1.178/artemis_model/redis/zone_state.py +111 -0
  27. artemis_model-0.1.178/artemis_model/schedule.py +90 -0
  28. artemis_model-0.1.178/artemis_model/setting.py +46 -0
  29. artemis_model-0.1.178/artemis_model/sqs/__init__.py +1 -0
  30. artemis_model-0.1.178/artemis_model/sqs/messages.py +122 -0
  31. artemis_model-0.1.178/artemis_model/track.py +112 -0
  32. artemis_model-0.1.178/artemis_model/user.py +65 -0
  33. artemis_model-0.1.178/artemis_model/zone.py +69 -0
  34. artemis_model-0.1.178/artemis_model/zone_activity.py +48 -0
  35. artemis_model-0.1.178/artemis_model/zone_state.py +88 -0
  36. artemis_model-0.1.178/pyproject.toml +99 -0
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: artemis-model
3
+ Version: 0.1.178
4
+ Summary:
5
+ Author: Jukeboxy
6
+ Requires-Python: >=3.10.6,<4.0.0
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.11
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Requires-Dist: alembic (>=1.13.1,<2.0.0)
13
+ Requires-Dist: asyncpg (>=0.30.0,<0.31.0)
14
+ Requires-Dist: greenlet (>=3.0.2,<4.0.0)
15
+ Requires-Dist: pydantic (>=2.10.2,<3.0.0)
16
+ Requires-Dist: python-slugify (>=8.0.4,<9.0.0)
17
+ Requires-Dist: sqlalchemy (>=2.0.23,<3.0.0)
18
+ Description-Content-Type: text/markdown
19
+
20
+ # artemis-model
21
+
22
+ Welcome to `artemis-model`, the backbone repository that contains all the essential models used in both the `artemis-api` and the `prophet` project. This project includes asynchronous models used by `artemis-api`, such as `Artist`, and synchronous models like `ArtistSync` for other implementations.
23
+
24
+ ## Getting Started
25
+
26
+ To set up your development environment for `artemis-model`, follow these initial setup steps:
27
+
28
+ 1. **Environment Setup**
29
+
30
+ ```shell
31
+ cp ./alembic/.env.example ./alembic/.env
32
+ ```
33
+
34
+ After copying the example environment file, make sure to fill in the `.env` file with your specific configurations.
35
+
36
+ 2. **Install Dependencies**
37
+
38
+ ```shell
39
+ poetry install --all-extras
40
+ ```
41
+
42
+ This will install all necessary dependencies to get you started with `artemis-models` and `alembic`.
43
+
44
+ ## Creating a New Model
45
+
46
+ To introduce a new model in the project, you should start by creating a mixin and then define two different model classes that inherit from this mixin.
47
+
48
+ ### Example: Adding a `LoginHistory` Model
49
+
50
+ 1. **Define the Mixin**
51
+ This mixin will include all the common attributes of your model.
52
+
53
+ ```python
54
+ class LoginHistoryMixin:
55
+ """
56
+ Stores the login history of users.
57
+ """
58
+
59
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, nullable=False)
60
+ account_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("user_account.id"), nullable=False, index=True)
61
+ ip_address: Mapped[str] = mapped_column(nullable=True)
62
+ created_at = mapped_column(DateTime, default=datetime.utcnow)
63
+
64
+ @declared_attr
65
+ def account(cls) -> Mapped["UserAccount"]:
66
+ return relationship("UserAccount", back_populates="login_histories")
67
+ ```
68
+
69
+ 2. **Inherit from Base Classes**
70
+ Create two classes that inherit from CustomBase and CustomSyncBase respectively, using the mixin for shared attributes.
71
+
72
+ ```python
73
+ class LoginHistorySync(CustomSyncBase, LoginHistoryMixin):
74
+ pass
75
+
76
+ class LoginHistory(CustomBase, LoginHistoryMixin):
77
+ pass
78
+ ```
79
+
80
+ ## Version Management and Builds
81
+
82
+ 1. **Update the Project Version**
83
+
84
+ Open pyproject.toml and increment the minor version number.
85
+
86
+ 2. **Build the Project**
87
+
88
+ ```shell
89
+ poetry build
90
+ ```
91
+
92
+ 3. **Update Dependency in artemis-api/prophet**
93
+
94
+ If the build succeeds, remember to also bump the version number in the pyproject.toml of artemis-api and prophet to match the new version of artemis-model.
95
+
96
+ ## Using Alembic for Model Changes
97
+
98
+ If modifications are necessary for any model:
99
+
100
+ 1. **Modify the Model**
101
+ 2. **Create an Alembic Revision**
102
+
103
+ ```shell
104
+ alembic revision --autogenerate -m "Description of changes"
105
+ ```
106
+
107
+ 3. **Upgrade Database Schema**
108
+
109
+ ```shell
110
+ alembic upgrade head
111
+ ```
112
+
113
+ Ensure that the new Alembic script in the versions directory is committed to your git repository.
114
+ Repeat the build and version update steps as necessary after making changes.
115
+
116
+
@@ -0,0 +1,96 @@
1
+ # artemis-model
2
+
3
+ Welcome to `artemis-model`, the backbone repository that contains all the essential models used in both the `artemis-api` and the `prophet` project. This project includes asynchronous models used by `artemis-api`, such as `Artist`, and synchronous models like `ArtistSync` for other implementations.
4
+
5
+ ## Getting Started
6
+
7
+ To set up your development environment for `artemis-model`, follow these initial setup steps:
8
+
9
+ 1. **Environment Setup**
10
+
11
+ ```shell
12
+ cp ./alembic/.env.example ./alembic/.env
13
+ ```
14
+
15
+ After copying the example environment file, make sure to fill in the `.env` file with your specific configurations.
16
+
17
+ 2. **Install Dependencies**
18
+
19
+ ```shell
20
+ poetry install --all-extras
21
+ ```
22
+
23
+ This will install all necessary dependencies to get you started with `artemis-models` and `alembic`.
24
+
25
+ ## Creating a New Model
26
+
27
+ To introduce a new model in the project, you should start by creating a mixin and then define two different model classes that inherit from this mixin.
28
+
29
+ ### Example: Adding a `LoginHistory` Model
30
+
31
+ 1. **Define the Mixin**
32
+ This mixin will include all the common attributes of your model.
33
+
34
+ ```python
35
+ class LoginHistoryMixin:
36
+ """
37
+ Stores the login history of users.
38
+ """
39
+
40
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, nullable=False)
41
+ account_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("user_account.id"), nullable=False, index=True)
42
+ ip_address: Mapped[str] = mapped_column(nullable=True)
43
+ created_at = mapped_column(DateTime, default=datetime.utcnow)
44
+
45
+ @declared_attr
46
+ def account(cls) -> Mapped["UserAccount"]:
47
+ return relationship("UserAccount", back_populates="login_histories")
48
+ ```
49
+
50
+ 2. **Inherit from Base Classes**
51
+ Create two classes that inherit from CustomBase and CustomSyncBase respectively, using the mixin for shared attributes.
52
+
53
+ ```python
54
+ class LoginHistorySync(CustomSyncBase, LoginHistoryMixin):
55
+ pass
56
+
57
+ class LoginHistory(CustomBase, LoginHistoryMixin):
58
+ pass
59
+ ```
60
+
61
+ ## Version Management and Builds
62
+
63
+ 1. **Update the Project Version**
64
+
65
+ Open pyproject.toml and increment the minor version number.
66
+
67
+ 2. **Build the Project**
68
+
69
+ ```shell
70
+ poetry build
71
+ ```
72
+
73
+ 3. **Update Dependency in artemis-api/prophet**
74
+
75
+ If the build succeeds, remember to also bump the version number in the pyproject.toml of artemis-api and prophet to match the new version of artemis-model.
76
+
77
+ ## Using Alembic for Model Changes
78
+
79
+ If modifications are necessary for any model:
80
+
81
+ 1. **Modify the Model**
82
+ 2. **Create an Alembic Revision**
83
+
84
+ ```shell
85
+ alembic revision --autogenerate -m "Description of changes"
86
+ ```
87
+
88
+ 3. **Upgrade Database Schema**
89
+
90
+ ```shell
91
+ alembic upgrade head
92
+ ```
93
+
94
+ Ensure that the new Alembic script in the versions directory is committed to your git repository.
95
+ Repeat the build and version update steps as necessary after making changes.
96
+
@@ -0,0 +1,22 @@
1
+ from artemis_model.album import * # noqa
2
+ from artemis_model.approved_playlist_list import * # noqa
3
+ from artemis_model.artist import * # noqa
4
+ from artemis_model.auth import * # noqa
5
+ from artemis_model.category import * # noqa
6
+ from artemis_model.dj_set import * # noqa
7
+ from artemis_model.genre import * # noqa
8
+ from artemis_model.location import * # noqa
9
+ from artemis_model.location_genre_exclusion import * # noqa
10
+ from artemis_model.message import * # noqa
11
+ from artemis_model.organization import * # noqa
12
+ from artemis_model.organization_include_pal_setting import * # noqa
13
+ from artemis_model.playlist import * # noqa
14
+ from artemis_model.schedule import * # noqa
15
+ from artemis_model.setting import * # noqa
16
+ from artemis_model.track import * # noqa
17
+ from artemis_model.user import * # noqa
18
+ from artemis_model.zone import * # noqa
19
+ from artemis_model.otp import * # noqa
20
+ from artemis_model.banned_tracks import * # noqa
21
+ from artemis_model.zone_activity import * # noqa
22
+ from artemis_model.zone_state import * # noqa
@@ -0,0 +1,69 @@
1
+ """Album models"""
2
+
3
+ from datetime import datetime
4
+
5
+ from sqlalchemy import Computed, ForeignKey, func, literal, text
6
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
7
+
8
+ from artemis_model.base import CustomSyncBase, CustomBase, TSVector, TimeStampMixin
9
+
10
+ from sqlalchemy.ext.declarative import declared_attr
11
+
12
+
13
+ def to_tsvector_ix(*columns):
14
+ s = " || ' ' || ".join(columns)
15
+ return func.to_tsvector(literal("english"), text(s))
16
+
17
+
18
+ class AlbumMixin(TimeStampMixin):
19
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
20
+ name: Mapped[str] = mapped_column(nullable=False)
21
+ description: Mapped[str | None] = mapped_column(nullable=True)
22
+ entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
23
+ disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
24
+ legacy_id: Mapped[str] = mapped_column(nullable=False)
25
+ is_internal: Mapped[bool] = mapped_column(nullable=False, default=False)
26
+
27
+ name_tsv = mapped_column(
28
+ TSVector(),
29
+ Computed("to_tsvector('english', name)", persisted=True),
30
+ )
31
+
32
+ # __table_args__ = (
33
+ # Index("fts_ix_album_name_tsv", to_tsvector_ix("name"), postgresql_using="gin"),
34
+ # )
35
+
36
+ @declared_attr
37
+ def artists(cls) -> Mapped[list["Artist"]]:
38
+ return relationship(secondary="album_artist_assoc", back_populates="albums")
39
+
40
+ @declared_attr
41
+ def tracks(cls) -> Mapped[list["Track"]]:
42
+ return relationship(
43
+ "Track",
44
+ back_populates="album",
45
+ cascade="all, delete-orphan",
46
+ )
47
+
48
+
49
+ class AlbumSync(CustomSyncBase, AlbumMixin):
50
+ pass
51
+
52
+
53
+ class Album(CustomBase, AlbumMixin):
54
+ pass
55
+
56
+
57
+ class AlbumArtistAssocMixin:
58
+ album_id: Mapped[int] = mapped_column(ForeignKey("album.id"), primary_key=True, nullable=False)
59
+ artist_id: Mapped[int] = mapped_column(
60
+ ForeignKey("artist.id"), primary_key=True, nullable=False
61
+ )
62
+
63
+
64
+ class AlbumArtistAssocSync(CustomSyncBase, AlbumArtistAssocMixin):
65
+ pass
66
+
67
+
68
+ class AlbumArtistAssoc(CustomBase, AlbumArtistAssocMixin):
69
+ pass
@@ -0,0 +1,55 @@
1
+ import uuid
2
+ from typing import List
3
+
4
+ from sqlalchemy import ForeignKey
5
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+ from sqlalchemy.ext.declarative import declared_attr
7
+
8
+ from artemis_model.base import CustomSyncBase, TimeStampMixin, AuditMixin, CustomBase
9
+
10
+
11
+ class ApprovedPlaylistListMixin(TimeStampMixin, AuditMixin):
12
+ id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True, index=True)
13
+ name: Mapped[str] = mapped_column(nullable=False)
14
+ organization_id: Mapped[uuid.UUID] = mapped_column(
15
+ ForeignKey("organization.id"), nullable=False, index=True
16
+ )
17
+
18
+ @declared_attr
19
+ def organization(cls) -> Mapped["Organization"]:
20
+ return relationship("Organization", back_populates="approved_playlist_lists")
21
+
22
+ @declared_attr
23
+ def playlist_associations(cls) -> Mapped[List["ApprovedPlaylistListPlaylistAssoc"]]:
24
+ return relationship(cascade="all, delete-orphan")
25
+
26
+ @declared_attr
27
+ def playlists(cls) -> Mapped[List["Playlist"]]:
28
+ return relationship(
29
+ "Playlist", secondary="approved_playlist_list_playlist_assoc", viewonly=True
30
+ )
31
+
32
+
33
+ class ApprovedPlaylistListSync(CustomSyncBase, ApprovedPlaylistListMixin):
34
+ pass
35
+
36
+
37
+ class ApprovedPlaylistList(CustomBase, ApprovedPlaylistListMixin):
38
+ pass
39
+
40
+
41
+ class ApprovedPlaylistListPlaylistAssocMixin(TimeStampMixin):
42
+ approved_playlist_list_id: Mapped[int] = mapped_column(
43
+ ForeignKey("approved_playlist_list.id"), primary_key=True, nullable=False
44
+ )
45
+ playlist_id: Mapped[int] = mapped_column(
46
+ ForeignKey("playlist.id"), primary_key=True, nullable=False
47
+ )
48
+
49
+
50
+ class ApprovedPlaylistListPlaylistAssocSync(CustomSyncBase, ApprovedPlaylistListPlaylistAssocMixin):
51
+ pass
52
+
53
+
54
+ class ApprovedPlaylistListPlaylistAssoc(CustomBase, ApprovedPlaylistListPlaylistAssocMixin):
55
+ pass
@@ -0,0 +1,49 @@
1
+ """Artist models"""
2
+
3
+ from datetime import datetime
4
+
5
+ from sqlalchemy import Computed, func, literal, text
6
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
7
+
8
+ from artemis_model.base import CustomBase, CustomSyncBase, TSVector, TimeStampMixin
9
+
10
+ from sqlalchemy.ext.declarative import declared_attr
11
+
12
+
13
+ def to_tsvector_ix(*columns):
14
+ s = " || ' ' || ".join(columns)
15
+ return func.to_tsvector(literal("english"), text(s))
16
+
17
+
18
+ class ArtistMixin(TimeStampMixin):
19
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
20
+ name: Mapped[str] = mapped_column(nullable=False)
21
+ entry_date: Mapped[datetime] = mapped_column(nullable=False, default=datetime.utcnow)
22
+ disabled: Mapped[bool] = mapped_column(nullable=False, default=False)
23
+ is_internal: Mapped[bool] = mapped_column(nullable=False, default=False)
24
+ legacy_id: Mapped[str] = mapped_column(nullable=False)
25
+
26
+ name_tsv = mapped_column(
27
+ TSVector(),
28
+ Computed("to_tsvector('english', name)", persisted=True),
29
+ )
30
+
31
+ # __table_args__ = (
32
+ # Index("fts_ix_artist_name_tsv", to_tsvector_ix("name"), postgresql_using="gin"),
33
+ # )
34
+
35
+ @declared_attr
36
+ def albums(cls) -> Mapped[list["Album"]]:
37
+ return relationship(secondary="album_artist_assoc", back_populates="artists")
38
+
39
+ @declared_attr
40
+ def tracks(cls) -> Mapped[list["Track"]]:
41
+ return relationship("Track", back_populates="artist", cascade="all, delete-orphan")
42
+
43
+
44
+ class ArtistSync(CustomSyncBase, ArtistMixin):
45
+ pass
46
+
47
+
48
+ class Artist(CustomBase, ArtistMixin):
49
+ pass
@@ -0,0 +1,184 @@
1
+ """Auth models."""
2
+
3
+ from enum import Enum
4
+ import uuid
5
+ from datetime import datetime
6
+ from typing import Optional
7
+
8
+ from pydantic import BaseModel
9
+ from sqlalchemy import UUID, DateTime, ForeignKey, LargeBinary
10
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
11
+ from sqlalchemy.ext.declarative import declared_attr
12
+
13
+ from artemis_model.base import CustomSyncBase, TimeStampMixin, CustomBase
14
+
15
+
16
+ class UserUnverifiedAccountMixin(TimeStampMixin):
17
+ """
18
+ This table is used to store the account info of users who have requested an account but have not yet
19
+ been verified. Once the user has been verified, the account will be moved to the UserAccount table.
20
+ """
21
+
22
+ id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
23
+ email: Mapped[str] = mapped_column(index=True)
24
+ name: Mapped[str] = mapped_column(nullable=False)
25
+ mobile: Mapped[str] = mapped_column(nullable=True, index=True)
26
+ is_root_user: Mapped[bool] = mapped_column(default=True)
27
+ is_email_verified: Mapped[bool] = mapped_column(default=False)
28
+ is_mobile_verified: Mapped[bool] = mapped_column(default=False)
29
+ is_onboarded: Mapped[bool] = mapped_column(default=False)
30
+ password = mapped_column(LargeBinary, nullable=False)
31
+ provider: Mapped[str] = mapped_column(default="internal")
32
+
33
+
34
+ class UserUnverifiedAccountSync(CustomSyncBase, UserUnverifiedAccountMixin):
35
+ pass
36
+
37
+
38
+ class UserUnverifiedAccount(CustomBase, UserUnverifiedAccountMixin):
39
+ pass
40
+
41
+
42
+ class UserAccountMixin(TimeStampMixin):
43
+ """
44
+ This table is used to store the account info of users who have been verified.
45
+ """
46
+
47
+ id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
48
+ email: Mapped[str] = mapped_column(index=True, unique=True)
49
+ name: Mapped[str] = mapped_column(nullable=False)
50
+ mobile: Mapped[Optional[str]] = mapped_column(nullable=True, unique=True, index=True)
51
+ password = mapped_column(LargeBinary, nullable=True)
52
+ provider: Mapped[str] = mapped_column(nullable=False)
53
+ oauth_id: Mapped[Optional[str]] = mapped_column(nullable=True, index=True)
54
+ image_url: Mapped[Optional[str]] = mapped_column(nullable=True)
55
+ is_email_verified: Mapped[bool] = mapped_column(default=False)
56
+ is_mobile_verified: Mapped[bool] = mapped_column(default=False)
57
+ is_root_user: Mapped[bool] = mapped_column(default=True)
58
+ is_super_admin: Mapped[bool] = mapped_column(default=False)
59
+ disabled: Mapped[bool] = mapped_column(default=False)
60
+ disabled_reason: Mapped[Optional[str]] = mapped_column(nullable=True)
61
+ is_onboarded: Mapped[bool] = mapped_column(default=False)
62
+
63
+ @declared_attr
64
+ def login_histories(cls) -> Mapped["LoginHistory"]:
65
+ return relationship("LoginHistory", back_populates="account")
66
+
67
+ @declared_attr
68
+ def user(cls) -> Mapped["User"]:
69
+ return relationship("User", back_populates="account")
70
+
71
+
72
+ class UserAccountSync(CustomSyncBase, UserAccountMixin):
73
+ pass
74
+
75
+
76
+ class UserAccount(CustomBase, UserAccountMixin):
77
+ pass
78
+
79
+
80
+ class LoginHistoryMixin:
81
+ """
82
+ This table is used to store the login history of users.
83
+ """
84
+
85
+ id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, nullable=False)
86
+ account_id: Mapped[uuid.UUID] = mapped_column(
87
+ ForeignKey("user_account.id"), nullable=False, index=True
88
+ )
89
+ ip_address: Mapped[str] = mapped_column(nullable=True)
90
+ created_at = mapped_column(DateTime, default=datetime.utcnow)
91
+
92
+ @declared_attr
93
+ def account(cls) -> Mapped["UserAccount"]:
94
+ return relationship("UserAccount", back_populates="login_histories")
95
+
96
+
97
+ class LoginHistorySync(CustomSyncBase, LoginHistoryMixin):
98
+ pass
99
+
100
+
101
+ class LoginHistory(CustomBase, LoginHistoryMixin):
102
+ pass
103
+
104
+
105
+ class OAuthCsrfStateMixin(TimeStampMixin):
106
+ id: Mapped[str] = mapped_column(primary_key=True, unique=True)
107
+ client_base_url: Mapped[str] = mapped_column(nullable=True)
108
+
109
+
110
+ class OAuthCsrfStateSync(CustomSyncBase, OAuthCsrfStateMixin):
111
+ pass
112
+
113
+
114
+ class OAuthCsrfState(CustomBase, OAuthCsrfStateMixin):
115
+ pass
116
+
117
+
118
+ class OrionWebplayerCodeMixin(TimeStampMixin):
119
+ """Orion webplayer code mixin."""
120
+
121
+ id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
122
+ code_hash: Mapped[str] = mapped_column(
123
+ unique=True, nullable=False
124
+ ) # Argon2id of normalized code
125
+ name: Mapped[str] = mapped_column(nullable=False)
126
+ zone_id: Mapped[int] = mapped_column(nullable=False, index=True)
127
+
128
+
129
+ class OrionWebplayerCodeSync(CustomSyncBase, OrionWebplayerCodeMixin):
130
+ pass
131
+
132
+
133
+ class OrionWebplayerCode(CustomBase, OrionWebplayerCodeMixin):
134
+ pass
135
+
136
+
137
+ class PlayerRefreshTokenMixin(TimeStampMixin):
138
+ """
139
+ Refresh token for Player.
140
+ We look up by token_id (PK), then verify `secret` against `secret_hash`.
141
+ """
142
+
143
+ # this is the public part we send to the client
144
+ id: Mapped[uuid.UUID] = mapped_column(
145
+ UUID(as_uuid=True),
146
+ primary_key=True,
147
+ default=uuid.uuid4,
148
+ )
149
+
150
+ code_id: Mapped[Optional[uuid.UUID]] = mapped_column(
151
+ UUID(as_uuid=True),
152
+ ForeignKey("orion_webplayer_code.id", ondelete="SET NULL"),
153
+ index=True,
154
+ nullable=True,
155
+ )
156
+
157
+ # store zone_id too (helps auth decisions / debugging)
158
+ zone_id: Mapped[Optional[int]] = mapped_column(index=True)
159
+
160
+ # bcrypt/argon2 hash of the secret part
161
+ secret_hash: Mapped[str] = mapped_column(nullable=False)
162
+
163
+
164
+ class PlayerRefreshTokenSync(CustomSyncBase, PlayerRefreshTokenMixin):
165
+ pass
166
+
167
+
168
+ class PlayerRefreshToken(CustomBase, PlayerRefreshTokenMixin):
169
+ pass
170
+
171
+
172
+ class Scope(str, Enum):
173
+ """Scope enum."""
174
+
175
+ PLAYER = "player"
176
+ MANAGE = "manage"
177
+
178
+ class TokenData(BaseModel):
179
+ """Token data."""
180
+
181
+ account_id: uuid.UUID
182
+ user_id: uuid.UUID
183
+ scope: Scope
184
+
@@ -0,0 +1,24 @@
1
+ """Banned Tracks per Zone Model"""
2
+
3
+ from sqlalchemy import UUID, Integer
4
+ from sqlalchemy.orm import Mapped, mapped_column
5
+ from artemis_model.base import AuditMixin, TimeStampMixin, CustomSyncBase, CustomBase
6
+
7
+
8
+ class BannedTracksMixin(TimeStampMixin, AuditMixin):
9
+ """Banned Tracks per Zone Model"""
10
+
11
+ zone_id: Mapped[int] = mapped_column(Integer, primary_key=True)
12
+ track_id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), primary_key=True)
13
+
14
+
15
+ class BannedTracksSync(CustomSyncBase, BannedTracksMixin):
16
+ """Banned Tracks per Zone Model"""
17
+
18
+ pass
19
+
20
+
21
+ class BannedTracks(CustomBase, BannedTracksMixin):
22
+ """Banned Tracks per Zone Model"""
23
+
24
+ pass