diff options
author | Jessica Tallon <tsyesika@tsyesika.se> | 2015-10-07 13:13:40 +0200 |
---|---|---|
committer | Jessica Tallon <tsyesika@tsyesika.se> | 2015-10-07 15:07:54 +0200 |
commit | d216d771f662fc3e0a3417ce06e8355abce99988 (patch) | |
tree | 7502682047ad22ec40d13d18ffb84a284d1e92ac /mediagoblin/db | |
parent | bc75a6532712e4b9b0f6d8b5bbd93db3ef58335d (diff) | |
download | mediagoblin-d216d771f662fc3e0a3417ce06e8355abce99988.tar.lz mediagoblin-d216d771f662fc3e0a3417ce06e8355abce99988.tar.xz mediagoblin-d216d771f662fc3e0a3417ce06e8355abce99988.zip |
Add public_id fixes throughout the code
This adds several things, mainly code which checks for the public id and
if it doesn't exist generating it where it can. This is to because we
need to keep the public_id to be able to effectively soft delete models.
This also adds a public_id field to the Activity along with a migration.
Diffstat (limited to 'mediagoblin/db')
-rw-r--r-- | mediagoblin/db/migrations.py | 29 | ||||
-rw-r--r-- | mediagoblin/db/mixin.py | 60 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 4 |
3 files changed, 70 insertions, 23 deletions
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 36ad736a..2df06fc0 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -1693,6 +1693,15 @@ def federation_collection_schema(db): # Add the fields onto the Collection model, we need to set these as # not null to avoid DB integreity errors. We will add the not null # constraint later. + public_id_column = Column( + "public_id", + Unicode, + unique=True + ) + public_id_column.create( + collection_table, + unique_name="collection_public_id") + updated_column = Column( "updated", DateTime, @@ -1846,3 +1855,23 @@ def federation_graveyard(db): # Commit changes to the db db.commit() + +@RegisterMigration(40, MIGRATIONS) +def add_public_id(db): + metadata = MetaData(bind=db.bind) + + # Get the table + activity_table = inspect_table(metadata, "core__activities") + activity_public_id = Column( + "public_id", + Unicode, + unique=True, + nullable=True + ) + activity_public_id.create( + activity_table, + unique_name="activity_public_id" + ) + + # Commit this. + db.commit() diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 7960061e..e6a2dc35 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -41,6 +41,40 @@ from mediagoblin.tools.text import cleaned_markdown_conversion from mediagoblin.tools.url import slugify from mediagoblin.tools.translate import pass_to_ugettext as _ +class GeneratePublicIDMixin(object): + """ + Mixin that ensures that a the public_id field is populated. + + The public_id is the ID that is used in the API, this must be globally + unique and dereferencable. This will be the URL for the API view of the + object. It's used in several places, not only is it used to give out via + the API but it's also vital information stored when a soft_deletion occurs + on the `Graveyard.public_id` field, this is needed to follow the spec which + says we have to be able to provide a shell of an object and return a 410 + (rather than a 404) when a deleted object has been deleted. + + This requires a the urlgen off the request object (`request.urlgen`) to be + provided as it's the ID is a URL. + """ + + def get_public_id(self, urlgen): + # Verify that the class this is on actually has a public_id field... + if "public_id" not in self.__table__.columns.keys(): + raise Exception("Model has no public_id field") + + # Great! the model has a public id, if it's None, let's create one! + if self.public_id is None: + # We need the internal ID for this so ensure we've been saved. + self.save(commit=False) + + # Create the URL + self.public_id = urlgen( + "mediagoblin.api.object", + object_type=self.object_type, + id=self.id, + qualified=True + ) + return self.public_id class UserMixin(object): object_type = "person" @@ -52,6 +86,7 @@ class UserMixin(object): def url_for_self(self, urlgen, **kwargs): """Generate a URL for this User's home page.""" return urlgen('mediagoblin.user_pages.user_home', + user=self.username, **kwargs) @@ -128,7 +163,7 @@ class GenerateSlugMixin(object): self.slug = slug -class MediaEntryMixin(GenerateSlugMixin): +class MediaEntryMixin(GenerateSlugMixin, GeneratePublicIDMixin): def check_slug_used(self, slug): # import this here due to a cyclic import issue # (db.models -> db.mixin -> db.util -> db.models) @@ -196,25 +231,6 @@ class MediaEntryMixin(GenerateSlugMixin): media=self.slug_or_id, **extra_args) - def get_public_id(self, request): - """ Returns the public_id of the MediaEntry - - If the MediaEntry has no public ID one will be produced from the - current request. - """ - if self.public_id is None: - self.public_id = request.urlgen( - "mediagoblin.api.object", - object_type=self.object_type, - id=self.id, - qualified=True - ) - # We need to ensure this ID is reused once we've given it out. - self.save() - - return self.public_id - - @property def thumb_url(self): """Return the thumbnail URL (for usage in templates) @@ -352,7 +368,7 @@ class MediaCommentMixin(object): comment=self.content) -class CollectionMixin(GenerateSlugMixin): +class CollectionMixin(GenerateSlugMixin, GeneratePublicIDMixin): object_type = "collection" def check_slug_used(self, slug): @@ -398,7 +414,7 @@ class CollectionItemMixin(object): """ return cleaned_markdown_conversion(self.note) -class ActivityMixin(object): +class ActivityMixin(GeneratePublicIDMixin): object_type = "activity" VALID_VERBS = ["add", "author", "create", "delete", "dislike", "favorite", diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 73f3c8ce..e52cab82 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -728,7 +728,7 @@ class MediaEntry(Base, MediaEntryMixin): author = self.get_actor published = UTC.localize(self.created) updated = UTC.localize(self.updated) - public_id = self.get_public_id(request) + public_id = self.get_public_id(request.urlgen) context = { "id": public_id, "author": author.serialize(request), @@ -1034,6 +1034,7 @@ class Collection(Base, CollectionMixin): __tablename__ = "core__collections" id = Column(Integer, primary_key=True) + public_id = Column(Unicode, unique=True) title = Column(Unicode, nullable=False) slug = Column(Unicode) created = Column(DateTime, nullable=False, default=datetime.datetime.utcnow, @@ -1492,6 +1493,7 @@ class Activity(Base, ActivityMixin): __tablename__ = "core__activities" id = Column(Integer, primary_key=True) + public_id = Column(Unicode, unique=True) actor = Column(Integer, ForeignKey("core__users.id"), nullable=False) |