class Vote(db.Model, SerializableObject): """Users are able to vote for the entries in the forum they like. Additionally to the score (-1 or +1) users are able to mark the entry as one of their favorites.""" __tablename__ = 'forum_vote' __table_args__ = (db.UniqueConstraint('entry_id', 'user_id'), {}) query = db.session.query_property(VoteQuery) #: Serializer attributes object_type = 'forum.vote' public_fields = ('id', 'entry_id', 'user', 'score', 'favorite') id = db.Column(db.Integer, primary_key=True) entry_id = db.Column(db.Integer, db.ForeignKey('forum_entry.entry_id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False) score = db.ColumnProperty(db.Column(db.Integer, nullable=False, default=0), extension=VoteScoreExtension()) favorite = db.Column(db.Boolean, nullable=False, default=False) user = db.relationship(User, backref='votes', lazy='joined', innerjoin=True)
class Answer(ForumEntry): __tablename__ = 'forum_answer' __mapper_args__ = { 'extension': SearchIndexMapperExtension('portal', 'answer'), 'polymorphic_identity': u'answer' } #: Serializer attributes object_type = 'forum.answer' public_fields = ('entry_id', 'discriminator', 'author', 'date_created', 'date_active', 'score', 'text', 'votes', 'question') id = db.Column(db.Integer, db.ForeignKey(ForumEntry.entry_id), primary_key=True) question_id = db.Column(db.Integer, db.ForeignKey(Question.id)) question = db.relationship(Question, backref=db.backref( 'answers', extension=QuestionAnswersExtension()), primaryjoin=(question_id == Question.id)) def get_url_values(self, **kwargs): """Generates an URL for this answer.""" kwargs.update({'entry_id': self.id}) return 'forum/answer', kwargs
class Event(db.Model, SerializableObject, TextRendererMixin): __tablename__ = 'event_event' __mapper_args__ = {'extension': db.SlugGenerator('slug', 'title')} # To order all queries by default, something like # __mapper_args__ = {'order_by':Event.start_date.asc() # has to be added to this class. No idea how to do that, now query = db.session.query_property(EventQuery) # serializer properties object_type = 'event.event' public_fields = ('id', 'title', 'slug', 'text', 'author', 'start', 'end', 'tags', 'discussion_question_id', 'info_question_id') #: Model columns id = db.Column(db.Integer, primary_key=True) title = db.Column(db.Unicode(100), nullable=False) slug = db.Column(db.Unicode(100), unique=True, index=True) text = db.Column(db.Text, nullable=False) author_id = db.Column(db.ForeignKey(User.id), nullable=False) start_date = db.Column(db.DateTime, nullable=False) end_date = db.Column(db.DateTime, nullable=False) tags = db.relationship(Tag, secondary=event_tag, backref=db.backref('events', lazy='dynamic'), lazy='joined', extension=TagCounterExtension()) discussion_question_id = db.Column(db.ForeignKey(Question.id), nullable=True) info_question_id = db.Column(db.ForeignKey(Question.id), nullable=True) author = db.relationship(User, lazy='joined') discussion_question = db.relationship( Question, primaryjoin=Question.id == discussion_question_id, backref=db.backref('eventd')) info_question = db.relationship( Question, primaryjoin=Question.id == info_question_id, backref=db.backref('eventi')) def get_url_values(self, action='view'): values = { 'view': 'event/view', 'browse': 'event/browse', 'calendar': 'event/calendar', 'edit': 'admin/event/edit', } return values[action], {'id': self.id} def __unicode__(self): return self.title
class Other(db.Model): __tablename__ = '_test_subscription_other' manager = TestResourceManager id = db.Column(db.Integer, primary_key=True) wrapper_id = db.Column(db.ForeignKey(Wrapper.id)) wrapper = db.relationship(Wrapper)
class TestSubscriptionComment(db.Model): __tablename__ = '_test_subscription_comment' manager = TestResourceManager id = db.Column(db.Integer, primary_key=True) entry_id = db.Column(db.ForeignKey(TestSubscriptionEntry.id), nullable=False) entry = db.relationship(TestSubscriptionEntry)
class TestSubscriptionEntry(db.Model): __tablename__ = '_test_subscription_entry' manager = TestResourceManager id = db.Column(db.Integer, primary_key=True) category_id = db.Column(db.ForeignKey(TestSubscriptionCategory.id)) category = db.relationship(TestSubscriptionCategory) title = db.Column(db.String(30))
class Comment(db.Model, TextRendererMixin): __tablename__ = 'news_comment' id = db.Column(db.Integer, primary_key=True) text = db.Column(db.Text, nullable=False) pub_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) deleted = db.Column(db.Boolean, nullable=False, default=False) author_id = db.Column(db.Integer, db.ForeignKey(User.id)) author = db.relationship(User, backref=db.backref('comments', lazy='dynamic')) article_id = db.Column(db.Integer, db.ForeignKey('news_article.id')) def get_url_values(self, action='view'): if action in ('hide', 'restore', 'edit'): return 'news/edit_comment', {'id': self.id, 'action': action} return 'news/detail', { 'slug': self.article.slug, '_anchor': 'comment_%s' % self.id } def __unicode__(self): return _(u'Comment by %s on %s') % (self.author.display_name, self.article.title)
class Question(ForumEntry): """A :class:`Question` is an :class:`ForumEntry` with a title, a slug and several tags.""" __tablename__ = 'forum_question' __mapper_args__ = { 'extension': (db.SlugGenerator('slug', 'title'), SearchIndexMapperExtension('portal', 'question')), 'polymorphic_identity': u'question' } query = db.session.query_property(QuestionQuery) #: Serializer attributes object_type = 'forum.question' public_fields = ('entry_id', 'discriminator', 'author', 'date_created', 'date_active', 'score', 'text', 'votes', 'tags', 'id', 'title', 'slug') id = db.Column(db.Integer, db.ForeignKey(ForumEntry.entry_id), primary_key=True) title = db.Column(db.Unicode(160), nullable=False) slug = db.Column(db.Unicode(160), nullable=False, index=True) answer_count = db.Column(db.Integer, default=0) tags = db.relationship(Tag, secondary=question_tag, lazy='subquery', backref=db.backref('questions', lazy='dynamic'), extension=TagCounterExtension()) def get_url_values(self, **kwargs): """Generates an URL for this question.""" action = kwargs.get('action') if action == 'vote-up': return 'forum/vote', {'entry_id': self.id, 'action': 'up'} elif action == 'vote-down': return 'forum/vote', {'entry_id': self.id, 'action': 'down'} kwargs.update({'slug': self.slug}) return 'forum/question', kwargs def __unicode__(self): return self.title
class Forum(db.Model, SerializableObject): __tablename__ = 'forum_forum' __mapper_args__ = {'extension': db.SlugGenerator('slug', 'name')} query = db.session.query_property(ForumQuery) #: serializer attributes object_type = 'forum.forum' public_fields = ('id', 'name', 'slug', 'description', 'tags' 'position', 'subforums') id = db.Column(db.Integer, primary_key=True) name = db.Column(db.Unicode(80), nullable=False) slug = db.Column(db.Unicode(80), unique=True, index=True) description = db.Column(db.Unicode(200), nullable=False, default=u'') parent_id = db.Column(db.Integer, db.ForeignKey(id), nullable=True, index=True) position = db.Column(db.Integer, nullable=False, default=0, index=True) subforums = db.relationship('Forum', backref=db.backref('parent', remote_side=id), lazy='joined') tags = db.relationship(Tag, secondary=forum_tag, lazy='dynamic', backref=db.backref('forums', lazy='dynamic'), extension=TagCounterExtension()) @cached_property def all_tags(self): """Return all tags for this forum, including those of the subforums.""" tags = list(self.tags) for subforum in self.subforums: tags.extend(subforum.tags) return tags def get_url_values(self, **kwargs): kwargs.update({'forum': self.slug}) return 'forum/questions', kwargs
class ForumEntry(db.Model, SerializableObject, TextRendererMixin): """The base class of a :class:`Question` or :class:`Answer`, which contains some general information about the author and the creation date, as well as the actual text and the votings.""" __tablename__ = 'forum_entry' query = db.session.query_property(ForumEntryQuery) #: Serializer attributes object_type = 'forum.entry' public_fields = ('entry_id', 'discriminator', 'author', 'date_created', 'date_active', 'score', 'text', 'votes') entry_id = db.Column(db.Integer, primary_key=True) discriminator = db.Column('type', db.Unicode(12)) author_id = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False) date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) date_active = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) score = db.Column(db.Integer, nullable=False, default=0) text = db.Column(db.Text, nullable=False) view_count = db.Column(db.Integer, default=0, nullable=False) author = db.relationship(User, lazy='joined', innerjoin=True) votes = db.relationship('Vote', backref='entry', extension=ForumEntryVotesExtension()) __mapper_args__ = {'polymorphic_on': discriminator} def touch(self): db.atomic_add(self, 'view_count', 1) def get_vote(self, user): return Vote.query.filter_by(user=user, entry=self).first()
class TestSubscriptionComment(db.Model): __tablename__ = '_test_subscription_comment' manager = TestResourceManager id = db.Column(db.Integer, primary_key=True) entry_id = db.Column(db.ForeignKey(TestSubscriptionEntry.id), nullable=False) entry = db.relationship(TestSubscriptionEntry) _entry_tag = db.Table( '_test_subscription_entry_tag', db.metadata, db.Column('entry_id', db.Integer, db.ForeignKey(TestSubscriptionEntry.id)), db.Column('tag_id', db.Integer, db.ForeignKey('_test_subscription_tag.id')), ) TestResourceManager.register_models(_entry_tag) class TestSubscriptionTag(db.Model): __tablename__ = '_test_subscription_tag' manager = TestResourceManager id = db.Column(db.Integer, primary_key=True) entries = db.relationship(TestSubscriptionEntry, secondary=_entry_tag, backref='tags',
class PasteEntry(db.Model, SerializableObject): __tablename__ = 'paste_entry' # serializer properties object_type = 'paste.entry' public_fields = ('id', 'text', 'title', 'author', 'pub_date', 'language', 'hidden') #: Model columns id = db.Column(db.Integer, primary_key=True) text = db.Column(db.Text, nullable=False) title = db.Column(db.Unicode(50), nullable=True) language = db.Column(db.Unicode(30)) author_id = db.Column(db.ForeignKey(User.id), nullable=False) pub_date = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) hidden = db.Column(db.Boolean, default=False) author = db.relationship(User, lazy='joined') # revision model implementation parent_id = db.Column(db.Integer, db.ForeignKey(id), nullable=True) children = db.relationship('PasteEntry', cascade='all', primaryjoin=parent_id == id, backref=db.backref('parent', remote_side=id)) def get_url_values(self, action='view'): if action == 'reply': return 'paste/index', {'reply_to': self.id} values = { 'view': 'paste/view', 'raw': 'paste/raw', 'show_tree': 'paste/show_tree', 'edit': 'paste/edit', } return values[action], {'id': self.id} @property def display_title(self): if self.title: return self.title return _(u'Paste #%d') % self.id @property def highlighted_text(self): return highlight_text(self.text, self.language) @property def has_tree(self): return bool(self.children) or bool(self.parent_id) def compare_to(self, other, column, context_lines=4, template=False): """Compare the model with another revision. Special version to enable highlighting between files. :param other: The other model instance to compare with. :param column: A string what column to compare. :param context_lines: How many additional lines to show on the udiff. :param template: Either or not to prepare the udiff for templates use. """ differ = generate_highlighted_udiff if template else generate_udiff generator = partial(differ, old=getattr(self, column, u''), new=getattr(other, column, u''), old_title=unicode(self), new_title=unicode(other), context_lines=context_lines) if template: udiff = generator(old_lang=self.language, new_lang=other.language) else: udiff = generator() if template: diff = prepare_udiff(udiff, True) return diff and diff[0] or None return udiff @classmethod def resolve_root(cls, identifier): """Find the root for a tree. :param identifier: The identifier a model should queried for. We use ``cls.query.get`` to query the identifier. :returns: The very root object with no additional parent_id set. """ obj = cls.query.get(identifier) if obj is None: return while obj.parent_id is not None: obj = obj.parent return obj def __unicode__(self): return self.display_title def __repr__(self): if self.title: s = repr(self.title) else: s = '#%s' % self.id if self.id else '[no id]' u = self.author.username return '<PasteEntry %s by %s>' % (s, u)
:copyright: 2009-2011 by the Inyoka Team, see AUTHORS for more details. :license: GNU GPL, see LICENSE for more details. """ import calendar from datetime import datetime, timedelta from inyoka.core.api import _, db from inyoka.core.mixins import TextRendererMixin from inyoka.core.auth.models import User from inyoka.core.models import Tag, TagCounterExtension from inyoka.core.serializer import SerializableObject from inyoka.forum.models import Question event_tag = db.Table( 'event_event_tag', db.metadata, db.Column('event_id', db.Integer, db.ForeignKey('event_event.id')), db.Column('tag_id', db.Integer, db.ForeignKey(Tag.id))) class EventQuery(db.Query): def start_in(self, year, month): """Return a query for all events that start in the given year and month :param year: The year that the event starts have to match :param month: The month that the event starts have to match """ days_in_month = calendar.monthrange(year, month)[1] interval_begin = datetime(year, month, 1, 0, 0, 0) interval_end = datetime(year, month, days_in_month, 23, 59, 59) q = self.filter( db.and_(Event.start_date >= interval_begin,
:copyright: 2010-2011 by the Inyoka Team, see AUTHORS for more details. :license: GNU GPL, see LICENSE for more details. """ from datetime import datetime from collections import defaultdict from werkzeug import cached_property from inyoka.core.api import _, db, SerializableObject from inyoka.core.auth.models import User from inyoka.core.models import Tag, TagCounterExtension from inyoka.core.mixins import TextRendererMixin from inyoka.core.search import SearchIndexMapperExtension from inyoka.portal.api import ITaggableContentProvider question_tag = db.Table( 'forum_question_tag', db.metadata, db.Column('question_id', db.Integer, db.ForeignKey('forum_question.id')), db.Column('tag_id', db.Integer, db.ForeignKey(Tag.id))) forum_tag = db.Table( 'forum_forum_tag', db.metadata, db.Column('forum_id', db.Integer, db.ForeignKey('forum_forum.id')), db.Column('tag_id', db.Integer, db.ForeignKey(Tag.id)), db.Column('propose', db.Boolean)) class QuestionsContentProvider(ITaggableContentProvider): type = 'forum_questions' name = _('Questions') def get_taggable_content(self, tag): return Question.query.order_by(Question.score, Question.view_count) \
class Article(db.Model, TextRendererMixin): __tablename__ = 'news_article' __mapper_args__ = { 'extension': (db.SlugGenerator('slug', 'title'), SearchIndexMapperExtension('portal', 'news'), db.GuidGenerator('news/article')) } query = db.session.query_property(ArticleQuery) id = db.Column(db.Integer, primary_key=True) pub_date = db.Column(db.DateTime, default=datetime.utcnow) updated = db.Column(db.DateTime, default=datetime.utcnow) title = db.Column(db.Unicode(200)) slug = db.Column(db.Unicode(100), unique=True) intro = db.Column(db.Text) text = db.Column(db.Text) public = db.Column(db.Boolean, default=False, nullable=False) view_count = db.Column(db.Integer, default=0, nullable=False) comment_count = db.Column(db.Integer, default=0, nullable=False) comments_enabled = db.Column(db.Boolean, default=True, nullable=False) guid = db.Column(db.Unicode(80), unique=True) tags = db.relationship(Tag, secondary=article_tag, backref=db.backref('articles', lazy='dynamic'), lazy='joined', extension=TagCounterExtension()) author_id = db.Column(db.ForeignKey(User.id), nullable=False) author = db.relationship(User, backref=db.backref('articles', lazy='dynamic')) comments = db.relationship(Comment, backref=db.backref('article', lazy='joined'), primaryjoin=id == Comment.article_id, order_by=[db.asc(Comment.pub_date)], lazy='dynamic', cascade='all, delete, delete-orphan', extension=CommentCounterExtension()) @property def hidden(self): """ This returns a boolean whether this article is not visible for normal users. Article that are not published or whose pub_date is in the future aren't shown for a normal user. """ return not self.public or self.pub_date > datetime.utcnow() @property def was_updated(self): return self.updated.replace(microsecond=0) > \ self.pub_date.replace(microsecond=0) def touch(self): db.atomic_add(self, 'view_count', 1) def get_url_values(self, **kwargs): action = kwargs.pop('action', 'view') if action in ('subscribe', 'unsubscribe'): return 'news/subscribe_comments', { 'slug': self.slug, 'action': action, } values = { 'view': 'news/detail', 'edit': 'news/article_edit', 'delete': 'news/article_delete', } kwargs.update({'slug': self.slug}) return values[action], kwargs def __unicode__(self): return self.title
Database models for the Inyoka News application. :copyright: 2009-2011 by the Inyoka Team, see AUTHORS for more details. :license: GNU GPL, see LICENSE for more details. """ from datetime import datetime, timedelta from inyoka.core.api import _, db from inyoka.core.auth.models import User from inyoka.core.mixins import TextRendererMixin from inyoka.core.models import Tag, TagCounterExtension from inyoka.core.search import SearchIndexMapperExtension from inyoka.portal.api import ITaggableContentProvider article_tag = db.Table( 'news_article_tag', db.metadata, db.Column('article_id', db.Integer, db.ForeignKey('news_article.id')), db.Column('tag_id', db.Integer, db.ForeignKey(Tag.id))) class ArticlesContentProvider(ITaggableContentProvider): type = 'news_articles' name = _('Articles') def get_taggable_content(self, tag): return tag.articles.order_by('view_count') class CommentCounterExtension(db.AttributeExtension): def append(self, state, value, initiator): instance = state.obj() instance.comment_count += 1