diff options
Diffstat (limited to 'mediagoblin/db')
-rw-r--r-- | mediagoblin/db/migrations.py | 75 | ||||
-rw-r--r-- | mediagoblin/db/mixin.py | 1 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 204 | ||||
-rw-r--r-- | mediagoblin/db/util.py | 20 |
4 files changed, 292 insertions, 8 deletions
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 374ab4c8..0eedc5d4 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -28,7 +28,8 @@ from migrate.changeset.constraint import UniqueConstraint from mediagoblin.db.extratypes import JSONEncoded from mediagoblin.db.migration_tools import RegisterMigration, inspect_table -from mediagoblin.db.models import MediaEntry, Collection, User, MediaComment +from mediagoblin.db.models import (MediaEntry, Collection, User, + MediaComment, Privilege, ReportBase) MIGRATIONS = {} @@ -299,6 +300,7 @@ def drop_token_related_User_columns(db): metadata = MetaData(bind=db.bind) user_table = inspect_table(metadata, 'core__users') + verification_key = user_table.columns['verification_key'] fp_verification_key = user_table.columns['fp_verification_key'] fp_token_expire = user_table.columns['fp_token_expire'] @@ -320,6 +322,7 @@ class CommentSubscription_v0(declarative_base()): user_id = Column(Integer, ForeignKey(User.id), nullable=False) + notify = Column(Boolean, nullable=False, default=True) send_email = Column(Boolean, nullable=False, default=True) @@ -380,6 +383,76 @@ def pw_hash_nullable(db): constraint = UniqueConstraint('username', table=user_table) constraint.create() +class ReportBase_v0(declarative_base()): + __tablename__ = 'core__reports' + id = Column(Integer, primary_key=True) + reporter_id = Column(Integer, ForeignKey(User.id), nullable=False) + report_content = Column(UnicodeText) + reported_user_id = Column(Integer, ForeignKey(User.id), nullable=False) + created = Column(DateTime, nullable=False, default=datetime.datetime.now) + discriminator = Column('type', Unicode(50)) + __mapper_args__ = {'polymorphic_on': discriminator} + +class CommentReport_v0(ReportBase_v0): + __tablename__ = 'core__reports_on_comments' + __mapper_args__ = {'polymorphic_identity': 'comment_report'} + + id = Column('id',Integer, ForeignKey('core__reports.id'), + primary_key=True) + comment_id = Column(Integer, ForeignKey(MediaComment.id), nullable=False) + +class MediaReport_v0(ReportBase_v0): + __tablename__ = 'core__reports_on_media' + __mapper_args__ = {'polymorphic_identity': 'media_report'} + + id = Column('id',Integer, ForeignKey('core__reports.id'), primary_key=True) + media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False) + +class ArchivedReport_v0(ReportBase_v0): + __tablename__ = 'core__reports_archived' + __mapper_args__ = {'polymorphic_identity': 'archived_report'} + + id = Column('id',Integer, ForeignKey('core__reports.id'), primary_key=True) + media_entry_id = Column(Integer, ForeignKey(MediaEntry.id)) + comment_id = Column(Integer, ForeignKey(MediaComment.id)) + resolver_id = Column(Integer, ForeignKey(User.id), nullable=False) + resolved_time = Column(DateTime) + result = Column(UnicodeText) + +class UserBan_v0(declarative_base()): + __tablename__ = 'core__user_bans' + user_id = Column('id',Integer, ForeignKey(User.id), nullable=False, + primary_key=True) + expiration_date = Column(DateTime) + reason = Column(UnicodeText, nullable=False) + +class Privilege_v0(declarative_base()): + __tablename__ = 'core__privileges' + id = Column(Integer, nullable=False, primary_key=True, unique=True) + privilege_name = Column(Unicode, nullable=False, unique=True) + +class PrivilegeUserAssociation_v0(declarative_base()): + __tablename__ = 'core__privileges_users' + group_id = Column( + 'core__privilege_id', + Integer, + ForeignKey(User.id), + primary_key=True) + user_id = Column( + 'core__user_id', + Integer, + ForeignKey(Privilege.id), + primary_key=True) + +@RegisterMigration(14, MIGRATIONS) +def create_moderation_tables(db): + ReportBase_v0.__table__.create(db.bind) + CommentReport_v0.__table__.create(db.bind) + MediaReport_v0.__table__.create(db.bind) + ArchivedReport_v0.__table__.create(db.bind) + UserBan_v0.__table__.create(db.bind) + Privilege_v0.__table__.create(db.bind) + PrivilegeUserAssociation_v0.__table__.create(db.bind) db.commit() diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 57b27d83..25ce6642 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -46,7 +46,6 @@ class UserMixin(object): def bio_html(self): return cleaned_markdown_conversion(self.bio) - class GenerateSlugMixin(object): """ Mixin to add a generate_slug method to objects. diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 9cb39ff4..25b4fa8f 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -104,6 +104,15 @@ class User(Base, UserMixin): super(User, self).delete(**kwargs) _log.info('Deleted user "{0}" account'.format(self.username)) + def has_privilege(self,*priv_names): + if len(priv_names) == 1: + priv = Privilege.query.filter( + Privilege.privilege_name==priv_names[0]).one() + return (priv in self.all_privileges) + elif len(priv_names) > 1: + return self.has_privilege(priv_names[0]) or \ + self.has_privilege(*priv_names[1:]) + return False class Client(Base): """ @@ -640,16 +649,195 @@ class ProcessingNotification(Notification): 'polymorphic_identity': 'processing_notification' } +class ReportBase(Base): + """ + This is the basic report table which the other reports are based off of. + :keyword reporter_id + :keyword report_content + :keyword reported_user_id + :keyword created + :keyword resolved + :keyword result + :keyword discriminator + + """ + __tablename__ = 'core__reports' + id = Column(Integer, primary_key=True) + reporter_id = Column(Integer, ForeignKey(User.id), nullable=False) + reporter = relationship( + User, + backref=backref("reports_filed_by", + lazy="dynamic", + cascade="all, delete-orphan"), + primaryjoin="User.id==ReportBase.reporter_id") + report_content = Column(UnicodeText) + reported_user_id = Column(Integer, ForeignKey(User.id), nullable=False) + reported_user = relationship( + User, + backref=backref("reports_filed_on", + lazy="dynamic", + cascade="all, delete-orphan"), + primaryjoin="User.id==ReportBase.reported_user_id") + created = Column(DateTime, nullable=False, default=datetime.datetime.now()) + discriminator = Column('type', Unicode(50)) + __mapper_args__ = {'polymorphic_on': discriminator} + + def is_comment_report(self): + return self.discriminator=='comment_report' + + def is_media_entry_report(self): + return self.discriminator=='media_report' + + def is_archived_report(self): + return self.discriminator=='archived_report' + + +class CommentReport(ReportBase): + """ + A class to keep track of reports that have been filed on comments + """ + __tablename__ = 'core__reports_on_comments' + __mapper_args__ = {'polymorphic_identity': 'comment_report'} + + id = Column('id',Integer, ForeignKey('core__reports.id'), + primary_key=True) + comment_id = Column(Integer, ForeignKey(MediaComment.id), nullable=False) + comment = relationship( + MediaComment, backref=backref("reports_filed_on", + lazy="dynamic", + cascade="all, delete-orphan")) + +class MediaReport(ReportBase): + """ + A class to keep track of reports that have been filed on media entries + """ + __tablename__ = 'core__reports_on_media' + __mapper_args__ = {'polymorphic_identity': 'media_report'} + + id = Column('id',Integer, ForeignKey('core__reports.id'), + primary_key=True) + media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False) + media_entry = relationship( + MediaEntry, + backref=backref("reports_filed_onmod/reports/1/", + lazy="dynamic", + cascade="all, delete-orphan")) + +class ArchivedReport(ReportBase): + """ + A table to keep track of reports that have been resolved + """ + __tablename__ = 'core__reports_archived' + __mapper_args__ = {'polymorphic_identity': 'archived_report'} + id = Column('id',Integer, ForeignKey('core__reports.id'), + primary_key=True) + + media_entry_id = Column(Integer, ForeignKey(MediaEntry.id)) + media_entry = relationship( + MediaEntry, + backref=backref("past_reports_filed_on", + lazy="dynamic")) + comment_id = Column(Integer, ForeignKey(MediaComment.id)) + comment = relationship( + MediaComment, backref=backref("past_reports_filed_on", + lazy="dynamic")) + + resolver_id = Column(Integer, ForeignKey(User.id), nullable=False) + resolver = relationship( + User, + backref=backref("reports_resolved_by", + lazy="dynamic", + cascade="all, delete-orphan"), + primaryjoin="User.id==ArchivedReport.resolver_id") + + resolved = Column(DateTime) + result = Column(UnicodeText) + +class UserBan(Base): + """ + Holds the information on a specific user's ban-state. As long as one of + these is attached to a user, they are banned from accessing mediagoblin. + When they try to log in, they are greeted with a page that tells them + the reason why they are banned and when (if ever) the ban will be + lifted + + :keyword user_id Holds the id of the user this object is + attached to. This is a one-to-one + relationship. + :keyword expiration_date Holds the date that the ban will be lifted. + If this is null, the ban is permanent + unless a moderator manually lifts it. + :keyword reason Holds the reason why the user was banned. + """ + __tablename__ = 'core__user_bans' + + user_id = Column(Integer, ForeignKey(User.id), nullable=False, + primary_key=True) + expiration_date = Column(DateTime) + reason = Column(UnicodeText, nullable=False) + + +class Privilege(Base): + """ + The Privilege table holds all of the different privileges a user can hold. + If a user 'has' a privilege, the User object is in a relationship with the + privilege object. + + :keyword privilege_name Holds a unicode object that is the recognizable + name of this privilege. This is the column + used for identifying whether or not a user + has a necessary privilege or not. + + """ + __tablename__ = 'core__privileges' + + id = Column(Integer, nullable=False, primary_key=True) + privilege_name = Column(Unicode, nullable=False, unique=True) + all_users = relationship( + User, + backref='all_privileges', + secondary="core__privileges_users") + + def __init__(self, privilege_name): + ''' + Currently consructors are required for tables that are initialized thru + the FOUNDATIONS system. This is because they need to be able to be con- + -structed by a list object holding their arg*s + ''' + self.privilege_name = privilege_name + + def __repr__(self): + return "<Privilege %s>" % (self.privilege_name) + + +class PrivilegeUserAssociation(Base): + ''' + This table holds the many-to-many relationship between User and Privilege + ''' + + __tablename__ = 'core__privileges_users' + + privilege_id = Column( + 'core__privilege_id', + Integer, + ForeignKey(User.id), + primary_key=True) + user_id = Column( + 'core__user_id', + Integer, + ForeignKey(Privilege.id), + primary_key=True) with_polymorphic( Notification, [ProcessingNotification, CommentNotification]) MODELS = [ - User, Client, RequestToken, AccessToken, NonceTimestamp, MediaEntry, Tag, - MediaTag, MediaComment, Collection, CollectionItem, MediaFile, FileKeynames, - MediaAttachmentFile, ProcessingMetaData, Notification, CommentNotification, - ProcessingNotification, CommentSubscription] + User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem, + MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData, + Notification, CommentNotification, ProcessingNotification, + CommentSubscription, ReportBase, CommentReport, MediaReport, UserBan, + Privilege, PrivilegeUserAssociation, ArchivedReport, ArchivedReport] """ Foundations are the default rows that are created immediately after the tables @@ -665,7 +853,13 @@ MODELS = [ FOUNDATIONS = {User:user_foundations} """ -FOUNDATIONS = {} +privilege_foundations = [{'privilege_name':u'admin'}, + {'privilege_name':u'moderator'}, + {'privilege_name':u'uploader'}, + {'privilege_name':u'reporter'}, + {'privilege_name':u'commenter'}, + {'privilege_name':u'active'}] +FOUNDATIONS = {Privilege:privilege_foundations} ###################################################### # Special, migrations-tracking table diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 8431361a..31fc49fb 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -15,7 +15,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from mediagoblin.db.base import Session -from mediagoblin.db.models import MediaEntry, Tag, MediaTag, Collection +from mediagoblin.db.models import (MediaEntry, Tag, MediaTag, Collection, \ + User, Privilege, FOUNDATIONS) ########################## @@ -67,6 +68,23 @@ def check_collection_slug_used(creator_id, slug, ignore_c_id): does_exist = Session.query(Collection.id).filter(filt).first() is not None return does_exist +def user_privileges_to_dictionary(user_id): + """ + This function accepts a users id and returns a dictionary of True or False + values for each privilege the user does or does not have. This allows for + easier referencing of a user's privileges inside templates. + """ + privilege_dictionary = {} + user = User.query.get(user_id) + users_privileges = [p_item.privilege_name for p_item in user.all_privileges] + #TODO update this to account for plugins that may add foundations + for privilege in FOUNDATIONS[Privilege]: + privilege_name = privilege['privilege_name'] + if privilege_name in users_privileges: + privilege_dictionary[privilege_name]=True + else: + privilege_dictionary[privilege_name]=False + return privilege_dictionary if __name__ == '__main__': from mediagoblin.db.open import setup_connection_and_db_from_config |