-
Notifications
You must be signed in to change notification settings - Fork 3
permission_model #140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
permission_model #140
Changes from all commits
d6466f9
3eb3e41
a35f591
082cd4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| """ | ||
| models/permission.py | ||
|
|
||
| This model defines the `Permission` table, a polymorphic table that tracks | ||
| all legal and administrative agreements related to site access and activity. | ||
| Its purpose is to track who granted permission, what activities they authorized, | ||
| which entity the permission applies to, and for what period of time. | ||
| """ | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| from sqlalchemy import ( | ||
| Integer, | ||
| ForeignKey, | ||
| String, | ||
| Boolean, | ||
| Date, | ||
| Text, | ||
| and_, | ||
| ) | ||
| from sqlalchemy.orm import relationship, Mapped, mapped_column, foreign | ||
|
|
||
| from db.base import Base, AutoBaseMixin, ReleaseMixin | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| from db.contact import Contact | ||
| from db.thing import Thing | ||
| from db.location import Location | ||
|
|
||
|
|
||
| class Permission(Base, AutoBaseMixin, ReleaseMixin): | ||
| """ | ||
| Represents a specific grant of permission from a Contact for a | ||
| specific entity (e.g., a Thing or Location). | ||
| """ | ||
|
|
||
| # --- Foreign Keys --- | ||
| contact_id: Mapped[int] = mapped_column( | ||
| Integer, ForeignKey("contact.contact_id"), nullable=False | ||
| ) | ||
|
|
||
| # --- Columns --- | ||
| allow_sampling: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) | ||
| allow_installation: Mapped[bool] = mapped_column( | ||
| Boolean, nullable=False, default=False | ||
| ) | ||
| start_date: Mapped[Date] = mapped_column(Date, nullable=True) | ||
| end_date: Mapped[Date] = mapped_column(Date, nullable=True) | ||
| notes: Mapped[str] = mapped_column(Text, nullable=True) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this relate back to the polymorphic notes table? rather than have a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of a polymorphic notes table, but thought it might be easier to implement single note fields in individual tables to start. Later we could go back and implement the polymorphic notes table, but I'm open to discussion. If we have the time I think it could be worth implementing now. We could still retain NMAquifer notes in |
||
|
|
||
| # --- Polymorphic Columns --- | ||
| permissible_id: Mapped[int] = mapped_column(Integer, nullable=False) | ||
| permissible_type: Mapped[str] = mapped_column(String(50), nullable=False) | ||
|
|
||
| # --- Relationships --- | ||
| # Many-To-One: A Permission is granted by one Contact. | ||
| contact: Mapped["Contact"] = relationship("Contact", back_populates="permissions") | ||
|
|
||
| # --- Polymorphic Parent Relationships (Internal) --- | ||
| # These are view-only relationships used by the 'target' property below. | ||
| # They tell SQLAlchemy exactly how to find the specific parent record for a given child. | ||
| _thing_target: Mapped["Thing"] = relationship( | ||
| "Thing", | ||
| primaryjoin=and_( | ||
| foreign(permissible_id) == Thing.thing_id, permissible_type == "Thing" | ||
| ), | ||
| viewonly=True, | ||
| ) | ||
| _location_target: Mapped["Location"] = relationship( | ||
| "Location", | ||
| primaryjoin=and_( | ||
| foreign(permissible_id) == Location.location_id, | ||
| permissible_type == "Location", | ||
| ), | ||
| viewonly=True, | ||
| ) | ||
|
Comment on lines
+63
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this to work do the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait! That's been noted in your notes. Should it be present in this PR? Or wait to implement that so that it can be implemented elsewhere, too, like services and tests?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. The idea with this PR is to just create the table. Then a separate PR for Thing and Location updates, where they would inherit these new tables. It seemed simpler to break down the PRs into their individual component tasks and focus on one thing at a time. Personal opinion of course, open to discussion re: best practices for PRs. |
||
|
|
||
| @property | ||
| def target(self): | ||
| """ | ||
| A generic property to get the parent object (Thing, Location, etc.). | ||
| This is useful for simplifying application code by providing a single, | ||
| consistent way to access the parent of a polymorphic record. | ||
| """ | ||
| return getattr(self, f"_{self.permissible_type.lower()}_target") | ||
Uh oh!
There was an error while loading. Please reload this page.