from sqlalchemy.sql import and_
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 = {}
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()
+
+
+ # oauth1 migrations
+ class Client_v0(declarative_base()):
+ """
+ Model representing a client - Used for API Auth
+ """
+ __tablename__ = "core__clients"
+
+ id = Column(Unicode, nullable=True, primary_key=True)
+ secret = Column(Unicode, nullable=False)
+ expirey = Column(DateTime, nullable=True)
+ application_type = Column(Unicode, nullable=False)
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ # optional stuff
+ redirect_uri = Column(JSONEncoded, nullable=True)
+ logo_url = Column(Unicode, nullable=True)
+ application_name = Column(Unicode, nullable=True)
+ contacts = Column(JSONEncoded, nullable=True)
+
+ def __repr__(self):
+ if self.application_name:
+ return "<Client {0} - {1}>".format(self.application_name, self.id)
+ else:
+ return "<Client {0}>".format(self.id)
+
+ class RequestToken_v0(declarative_base()):
+ """
+ Model for representing the request tokens
+ """
+ __tablename__ = "core__request_tokens"
+
+ token = Column(Unicode, primary_key=True)
+ secret = Column(Unicode, nullable=False)
+ client = Column(Unicode, ForeignKey(Client_v0.id))
+ user = Column(Integer, ForeignKey(User.id), nullable=True)
+ used = Column(Boolean, default=False)
+ authenticated = Column(Boolean, default=False)
+ verifier = Column(Unicode, nullable=True)
+ callback = Column(Unicode, nullable=False, default=u"oob")
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ class AccessToken_v0(declarative_base()):
+ """
+ Model for representing the access tokens
+ """
+ __tablename__ = "core__access_tokens"
+
+ token = Column(Unicode, nullable=False, primary_key=True)
+ secret = Column(Unicode, nullable=False)
+ user = Column(Integer, ForeignKey(User.id))
+ request_token = Column(Unicode, ForeignKey(RequestToken_v0.token))
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+
+ class NonceTimestamp_v0(declarative_base()):
+ """
+ A place the timestamp and nonce can be stored - this is for OAuth1
+ """
+ __tablename__ = "core__nonce_timestamps"
+
+ nonce = Column(Unicode, nullable=False, primary_key=True)
+ timestamp = Column(DateTime, nullable=False, primary_key=True)
+
+
+ @RegisterMigration(14, MIGRATIONS)
+ def create_oauth1_tables(db):
+ """ Creates the OAuth1 tables """
+
+ Client_v0.__table__.create(db.bind)
+ RequestToken_v0.__table__.create(db.bind)
+ AccessToken_v0.__table__.create(db.bind)
+ NonceTimestamp_v0.__table__.create(db.bind)
+
+ db.commit()
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):
+ """
+ Model representing a client - Used for API Auth
+ """
+ __tablename__ = "core__clients"
+
+ id = Column(Unicode, nullable=True, primary_key=True)
+ secret = Column(Unicode, nullable=False)
+ expirey = Column(DateTime, nullable=True)
+ application_type = Column(Unicode, nullable=False)
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ # optional stuff
+ redirect_uri = Column(JSONEncoded, nullable=True)
+ logo_url = Column(Unicode, nullable=True)
+ application_name = Column(Unicode, nullable=True)
+ contacts = Column(JSONEncoded, nullable=True)
+
+ def __repr__(self):
+ if self.application_name:
+ return "<Client {0} - {1}>".format(self.application_name, self.id)
+ else:
+ return "<Client {0}>".format(self.id)
+
+ class RequestToken(Base):
+ """
+ Model for representing the request tokens
+ """
+ __tablename__ = "core__request_tokens"
+
+ token = Column(Unicode, primary_key=True)
+ secret = Column(Unicode, nullable=False)
+ client = Column(Unicode, ForeignKey(Client.id))
+ user = Column(Integer, ForeignKey(User.id), nullable=True)
+ used = Column(Boolean, default=False)
+ authenticated = Column(Boolean, default=False)
+ verifier = Column(Unicode, nullable=True)
+ callback = Column(Unicode, nullable=False, default=u"oob")
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ class AccessToken(Base):
+ """
+ Model for representing the access tokens
+ """
+ __tablename__ = "core__access_tokens"
+
+ token = Column(Unicode, nullable=False, primary_key=True)
+ secret = Column(Unicode, nullable=False)
+ user = Column(Integer, ForeignKey(User.id))
+ request_token = Column(Unicode, ForeignKey(RequestToken.token))
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+
+ class NonceTimestamp(Base):
+ """
+ A place the timestamp and nonce can be stored - this is for OAuth1
+ """
+ __tablename__ = "core__nonce_timestamps"
+
+ nonce = Column(Unicode, nullable=False, primary_key=True)
+ timestamp = Column(DateTime, nullable=False, primary_key=True)
+
class MediaEntry(Base, MediaEntryMixin):
"""
Notification,
[ProcessingNotification, CommentNotification])
-
MODELS = [
- User, MediaEntry, Tag, MediaTag, MediaComment, Collection, CollectionItem,
- MediaFile, FileKeynames, MediaAttachmentFile, ProcessingMetaData, ReportBase,
- CommentReport, MediaReport, UserBan, Privilege, PrivilegeUserAssociation,
- ArchivedReport, Notification, CommentNotification,
- ProcessingNotification, CommentSubscription]
- 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
+ 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:
ModelConstructorObject:List of Dictionaries
(Each Dictionary represents a row on the Table to be created, containing each
from mediagoblin import mg_globals as mgg
from mediagoblin import messages
-from mediagoblin.db.models import MediaEntry, User
-from mediagoblin.tools.response import json_response, redirect, render_404
+from mediagoblin.db.models import (MediaEntry, User, MediaComment,
+ UserBan, Privilege)
- from mediagoblin.tools.response import redirect, render_404, render_user_banned
++from mediagoblin.tools.response import (redirect, render_404,
++ render_user_banned, json_response)
from mediagoblin.tools.translate import pass_to_ugettext as _
+ from mediagoblin.oauth.tools.request import decode_authorization_header
+ from mediagoblin.oauth.oauth import GMGRequestValidator
def require_active_login(controller):
"""
return wrapper
- def get_workbench(func):
- """Decorator, passing in a workbench as kwarg which is cleaned up afterwards"""
- @wraps(func)
- def new_func(*args, **kwargs):
- with mgg.workbench_manager.create() as workbench:
- return func(*args, workbench=workbench, **kwargs)
- return new_func
-
+def require_admin_or_moderator_login(controller):
+ """
+ Require an login from an administrator or a moderator.
+ """
+ @wraps(controller)
+ def new_controller_func(request, *args, **kwargs):
+ if request.user and \
+ not request.user.has_privilege(u'admin',u'moderator'):
+
+ 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
+
++
+def user_not_banned(controller):
+ """
+ Requires that the user has not been banned. Otherwise redirects to the page
+ explaining why they have been banned
+ """
+ @wraps(controller)
+ def wrapper(request, *args, **kwargs):
+ if request.user:
+ user_banned = UserBan.query.get(request.user.id)
+ if user_banned:
+ return render_user_banned(request)
+ return controller(request, *args, **kwargs)
+
+ return wrapper
+
++
++
+ def oauth_required(controller):
+ """ Used to wrap API endpoints where oauth is required """
+ @wraps(controller)
+ def wrapper(request, *args, **kwargs):
+ data = request.headers
+ authorization = decode_authorization_header(data)
+
+ if authorization == dict():
+ error = "Missing required parameter."
+ return json_response({"error": error}, status=400)
+
+
+ request_validator = GMGRequestValidator()
+ resource_endpoint = ResourceEndpoint(request_validator)
+ valid, request = resource_endpoint.validate_protected_resource_request(
+ uri=request.url,
+ http_method=request.method,
+ body=request.get_data(),
+ headers=dict(request.headers),
+ )
+
+ if not valid:
+ error = "Invalid oauth prarameter."
+ return json_response({"error": error}, status=400)
+
+ return controller(request, *args, **kwargs)
+
+ return wrapper
collection_description = wtforms.TextAreaField(
_('Description of this collection'),
description=_("""You can use
- <a href="http://daringfireball.net/projects/markdown/basics">
+ <a href="http://daringfireball.net/projects/markdown/basics" target="_blank">
Markdown</a> for formatting."""))
+
+class CommentReportForm(wtforms.Form):
+ report_reason = wtforms.TextAreaField(
+ _('Reason for Reporting'),
+ [wtforms.validators.Required()])
+ reporter_id = wtforms.HiddenField('')
+
+class MediaReportForm(wtforms.Form):
+ report_reason = wtforms.TextAreaField(
+ _('Reason for Reporting'),
+ [wtforms.validators.Required()])
+ reporter_id = wtforms.HiddenField('')
from mediagoblin import messages, mg_globals
from mediagoblin.db.models import (MediaEntry, MediaTag, Collection,
- CollectionItem, User)
+ CollectionItem, User, MediaComment,
+ CommentReport, MediaReport)
from mediagoblin.tools.response import render_to_response, render_404, \
redirect, redirect_obj
+ from mediagoblin.tools.text import cleaned_markdown_conversion
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.pagination import Pagination
from mediagoblin.user_pages import forms as user_forms