diff options
-rw-r--r-- | mediagoblin/admin/views.py | 35 | ||||
-rw-r--r-- | mediagoblin/db/migration_tools.py | 17 | ||||
-rw-r--r-- | mediagoblin/db/migrations.py | 37 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 85 | ||||
-rw-r--r-- | mediagoblin/decorators.py | 45 | ||||
-rw-r--r-- | mediagoblin/user_pages/forms.py | 6 | ||||
-rw-r--r-- | mediagoblin/user_pages/lib.py | 15 | ||||
-rw-r--r-- | mediagoblin/user_pages/views.py | 22 |
8 files changed, 175 insertions, 87 deletions
diff --git a/mediagoblin/admin/views.py b/mediagoblin/admin/views.py index faa8603a..7a4dfbd4 100644 --- a/mediagoblin/admin/views.py +++ b/mediagoblin/admin/views.py @@ -17,18 +17,14 @@ from werkzeug.exceptions import Forbidden from mediagoblin.db.models import MediaEntry, User, MediaComment, CommentReport, ReportBase -from mediagoblin.decorators import require_active_login +from mediagoblin.decorators import require_admin_login from mediagoblin.tools.response import render_to_response -@require_active_login +@require_admin_login def admin_processing_panel(request): ''' - Show the global processing panel for this instance + Show the global media processing panel for this instance ''' - # TODO: Why not a "require_admin_login" decorator throwing a 403 exception? - if not request.user.is_admin: - raise Forbidden() - processing_entries = MediaEntry.query.filter_by(state = u'processing').\ order_by(MediaEntry.created.desc()) @@ -47,15 +43,11 @@ def admin_processing_panel(request): 'failed_entries': failed_entries, 'processed_entries': processed_entries}) -@require_active_login +@require_admin_login def admin_users_panel(request): ''' - Show the global processing panel for this instance + Show the global panel for monitoring users in this instance ''' - # TODO: Why not a "require_admin_login" decorator throwing a 403 exception? - if not request.user.is_admin: - raise Forbidden() - user_list = User.query # Render to response @@ -64,17 +56,18 @@ def admin_users_panel(request): 'mediagoblin/admin/user.html', {'user_list': user_list}) -@require_active_login +@require_admin_login def admin_reports_panel(request): ''' - Show the global processing panel for this instance + Show the global panel for monitoring reports filed against comments or + media entries for this instance. ''' - # TODO: Why not a "require_admin_login" decorator throwing a 403 exception? - if not request.user.is_admin: - raise Forbidden() - - report_list = ReportBase.query.filter(ReportBase.resolved==None).order_by(ReportBase.created.desc()).limit(10) - closed_report_list = ReportBase.query.filter(ReportBase.resolved!=None).order_by(ReportBase.created.desc()).limit(10) + report_list = ReportBase.query.filter( + ReportBase.resolved==None).order_by( + ReportBase.created.desc()).limit(10) + closed_report_list = ReportBase.query.filter( + ReportBase.resolved!=None).order_by( + ReportBase.created.desc()).limit(10) # Render to response return render_to_response( diff --git a/mediagoblin/db/migration_tools.py b/mediagoblin/db/migration_tools.py index c0c7e998..f100f47e 100644 --- a/mediagoblin/db/migration_tools.py +++ b/mediagoblin/db/migration_tools.py @@ -140,6 +140,17 @@ class MigrationManager(object): self.session.bind, tables=[model.__table__ for model in self.models]) + def populate_table_foundations(self): + """ + Create the table foundations (default rows) as layed out in FOUNDATIONS + in mediagoblin.db.models + """ + from mediagoblin.db.models import FOUNDATIONS as MAIN_FOUNDATIONS + for Model in MAIN_FOUNDATIONS.keys(): + for parameters in MAIN_FOUNDATIONS[Model]: + row = Model(*parameters) + row.save() + def create_new_migration_record(self): """ Create a new migration record for this migration set @@ -203,8 +214,10 @@ class MigrationManager(object): self.init_tables() # auto-set at latest migration number - self.create_new_migration_record() - + self.create_new_migration_record() + if self.name==u'__main__': + self.populate_table_foundations() + self.printer(u"done.\n") self.set_current_migration() return u'inited' diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py index 110a48d4..5e9a71d4 100644 --- a/mediagoblin/db/migrations.py +++ b/mediagoblin/db/migrations.py @@ -314,16 +314,13 @@ 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) + id = Column( + 'id', + Integer, + ForeignKey('core__reports.id'), + primary_key=True) media_entry_id = Column(Integer, ForeignKey(MediaEntry.id), nullable=False) -@RegisterMigration(11, MIGRATIONS) -def create_report_tables(db): - ReportBase_v0.__table__.create(db.bind) - CommentReport_v0.__table__.create(db.bind) - MediaReport_v0.__table__.create(db.bind) - db.commit() class UserBan_v0(declarative_base()): __tablename__ = 'core__user_bans' @@ -334,23 +331,31 @@ class UserBan_v0(declarative_base()): class Group_v0(declarative_base()): __tablename__ = 'core__groups' - id = Column(Integer, nullable=False, primary_key=True) + id = Column(Integer, nullable=False, primary_key=True, unique=True) group_name = Column(Unicode, nullable=False) class GroupUserAssociation_v0(declarative_base()): __tablename__ = 'core__group_user_associations' - group_id = Column('core__group_id', Integer, ForeignKey(User.id), primary_key=True) - user_id = Column('core__user_id', Integer, ForeignKey(Group.id), primary_key=True) + group_id = Column( + 'core__group_id', + Integer, + ForeignKey(User.id), + primary_key=True) + user_id = Column( + 'core__user_id', + Integer, + ForeignKey(Group.id), + primary_key=True) - - -@RegisterMigration(12, MIGRATIONS) -def create_banned_and_group_tables(db): +@RegisterMigration(11, MIGRATIONS) +def create_moderation_tables(db): + ReportBase_v0.__table__.create(db.bind) + CommentReport_v0.__table__.create(db.bind) + MediaReport_v0.__table__.create(db.bind) UserBan_v0.__table__.create(db.bind) Group_v0.__table__.create(db.bind) GroupUserAssociation_v0.__table__.create(db.bind) db.commit() - diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index f524b220..28e01a85 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -492,11 +492,13 @@ class ReportBase(Base): __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")) + reporter = relationship( + User, + backref=backref("reports_filed_by", + lazy="dynamic", + cascade="all, delete-orphan")) report_content = Column(UnicodeText) - created = Column(DateTime, nullable=False, default=datetime.datetime.now()) + created = Column(DateTime, nullable=False, default=datetime.datetime.now()) resolved = Column(DateTime) discriminator = Column('type', Unicode(50)) __mapper_args__ = {'polymorphic_on': discriminator} @@ -512,9 +514,10 @@ class CommentReport(ReportBase): 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")) + comment = relationship( + MediaComment, backref=backref("reports_filed_on", + lazy="dynamic", + cascade="all, delete-orphan")) class MediaReport(ReportBase): """ @@ -526,27 +529,32 @@ class MediaReport(ReportBase): 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_on", - lazy="dynamic", - cascade="all, delete-orphan")) + media_entry = relationship( + MediaEntry, + backref=backref("reports_filed_on", + lazy="dynamic", + cascade="all, delete-orphan")) 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 - :param user_id Holds the id of the user this object is attached to. - This should be a one-to-one relationship. - :param 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. + 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 + + :param user_id Holds the id of the user this object is + attached to. This is a one-to-one + relationship. + :param 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. :param reason Holds the reason why the user was banned. """ __tablename__ = 'core__user_bans' - user_id = Column('id',Integer, ForeignKey(User.id), nullable=False, - primary_key=True) + user_id = Column(Integer, ForeignKey(User.id), nullable=False, + primary_key=True) expiration_date = Column(DateTime) reason = Column(UnicodeText, nullable=False) @@ -555,8 +563,14 @@ class Group(Base): __tablename__ = 'core__groups' id = Column(Integer, nullable=False, primary_key=True) - group_name = Column(Unicode, nullable=False) - all_users = relationship(User, backref='all_groups', secondary="core__group_user_associations") + group_name = Column(Unicode, nullable=False, unique=True) + all_users = relationship( + User, + backref='all_groups', + secondary="core__group_user_associations") + + def __init__(self, group_name): + self.group_name = group_name def __repr__(self): return "<Group %s>" % (self.group_name) @@ -564,14 +578,31 @@ class Group(Base): class GroupUserAssociation(Base): __tablename__ = 'core__group_user_associations' - group_id = Column('core__group_id', Integer, ForeignKey(User.id), primary_key=True) - user_id = Column('core__user_id', Integer, ForeignKey(Group.id), primary_key=True) + group_id = Column( + 'core__group_id', + Integer, + ForeignKey(User.id), + primary_key=True) + user_id = Column( + 'core__user_id', + Integer, + ForeignKey(Group.id), + primary_key=True) +group_foundations = [[u'admin'], [u'moderator'], [u'commenter'], [u'uploader'],[u'reporter'],[u'active']] MODELS = [ - User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem, MediaFile, FileKeynames, - MediaAttachmentFile, ProcessingMetaData, CommentReport, MediaReport, UserBan, Group, GroupUserAssociation] + User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem, + MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData, ReportBase, + CommentReport, MediaReport, UserBan, Group, GroupUserAssociation] + +# Foundations are the default rows that are created immediately after the tables are initialized. Each entry to +# this dictionary should be in the format of +# ModelObject:List of Rows +# (Each Row must be a list of parameters that can create and instance of the ModelObject) +# +FOUNDATIONS = {Group:group_foundations} ###################################################### # Special, migrations-tracking table diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py index 5b55ead7..d54bf050 100644 --- a/mediagoblin/decorators.py +++ b/mediagoblin/decorators.py @@ -21,7 +21,7 @@ from werkzeug.exceptions import Forbidden, NotFound from werkzeug.urls import url_quote from mediagoblin import mg_globals as mgg -from mediagoblin.db.models import MediaEntry, User, MediaComment +from mediagoblin.db.models import MediaEntry, User, MediaComment, Group from mediagoblin.tools.response import redirect, render_404 @@ -63,6 +63,26 @@ def active_user_from_url(controller): return wrapper +def user_in_group(group_name): +#TODO handle possible errors correctly + def user_in_group_decorator(controller): + @wraps(controller) + + def wrapper(request, *args, **kwargs): + user_id = request.user.id + group = Group.query.filter( + Group.group_name==group_name).first() + if not (group.query.filter( + Group.all_users.any( + User.id==user_id)).count()): + + raise Forbidden() + + return controller(request, *args, **kwargs) + + return wrapper + return user_in_group_decorator + def user_may_delete_media(controller): """ @@ -253,3 +273,26 @@ def get_workbench(func): return func(*args, workbench=workbench, **kwargs) return new_func + +def require_admin_login(controller): + """ + Require an login from an administrator. + """ + @wraps(controller) + def new_controller_func(request, *args, **kwargs): + if request.user and \ + not request.user.is_admin: + raise Forbidden() + elif not request.user: + next_url = urljoin( + request.urlgen('mediagoblin.auth.login', + qualified=True), + request.url) + + return redirect(request, 'mediagoblin.auth.login', + next=next_url) + + return controller(request, *args, **kwargs) + + return new_controller_func + diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index effe49e1..284dd7b8 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -59,9 +59,3 @@ class MediaReportForm(wtforms.Form): report_reason = wtforms.TextAreaField('Reason for Reporting') media_entry_id = wtforms.IntegerField() reporter_id = wtforms.IntegerField() - -class ReportForm(wtforms.Form): - report_reason = wtforms.TextAreaField('Reason for Reporting') - media_entry_id = wtforms.IntegerField() - reporter_id = wtforms.IntegerField() - comment_id = wtforms.IntegerField() diff --git a/mediagoblin/user_pages/lib.py b/mediagoblin/user_pages/lib.py index 9c8ddee6..557c4853 100644 --- a/mediagoblin/user_pages/lib.py +++ b/mediagoblin/user_pages/lib.py @@ -79,12 +79,15 @@ def add_media_to_collection(collection, media, note=None, commit=True): def build_report_form(form_dict): """ - :param form_dict should be an ImmutableMultiDict object which is what is - returned from 'request.form.' The Object should have valid keys - matching the fields in either MediaReportForm or CommentReportForm + This function is used to convert a form dictionary (from a User filing a + report) into either a MediaReport or CommentReport object. - :returns either of MediaReport or a CommentReport object that has not been saved. - In case of an improper form_dict, returns None + :param form_dict should be an ImmutableMultiDict object as is returned from + 'request.form.' The Object should have valid keys matching the fields + in either MediaReportForm or CommentReportForm + + :returns either of MediaReport or a CommentReport object that has not been + saved. In case of an improper form_dict, returns None """ if 'comment_id' in form_dict.keys(): report_form = user_forms.CommentReportForm(form_dict) @@ -92,6 +95,7 @@ def build_report_form(form_dict): report_form = user_forms.MediaReportForm(form_dict) else: return None + if report_form.validate() and 'comment_id' in form_dict.keys(): report_model = CommentReport() report_model.comment_id = report_form.comment_id.data @@ -100,6 +104,7 @@ def build_report_form(form_dict): report_model.media_entry_id = report_form.media_entry_id.data else: return None + report_model.report_content = report_form.report_reason.data or u'' report_model.reporter_id = report_form.reporter_id.data return report_model diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 94cccc66..a0eb67db 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -20,7 +20,7 @@ import datetime from mediagoblin import messages, mg_globals from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, CollectionItem, User, MediaComment, - CommentReport, MediaReport) + CommentReport, MediaReport, Group) from mediagoblin.tools.response import render_to_response, render_404, \ redirect, redirect_obj from mediagoblin.tools.translate import pass_to_ugettext as _ @@ -30,7 +30,7 @@ from mediagoblin.user_pages.lib import (send_comment_email, build_report_form, add_media_to_collection) from mediagoblin.decorators import (uses_pagination, get_user_media_entry, - get_media_entry_by_id, + get_media_entry_by_id, user_in_group, require_active_login, user_may_delete_media, user_may_alter_collection, get_user_collection, get_user_collection_item, active_user_from_url, get_media_comment_by_id) @@ -621,22 +621,26 @@ def processing_panel(request): @require_active_login @get_user_media_entry -def file_a_report(request, media, comment=None): +@user_in_group(u'reporter') +def file_a_report(request, media, comment=None, required_group=1): if request.method == "POST": report_form = build_report_form(request.form) report_form.save() + return redirect( - request, - 'index') + request, + 'index') + if comment is not None: context = {'media': media, - 'comment':comment} + 'comment':comment} else: context = {'media': media} + return render_to_response( - request, - 'mediagoblin/user_pages/report.html', - context) + request, + 'mediagoblin/user_pages/report.html', + context) @require_active_login @get_user_media_entry |