def view_forum(forum_id, slug=None): page = request.args.get('page', 1, type=int) if current_user.is_authenticated(): forum = Forum.query.\ filter(Forum.id == forum_id).\ options(db.joinedload("category")).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == current_user.id)).\ add_entity(ForumsRead).\ first_or_404() topics = Topic.query.filter_by(forum_id=forum[0].id).\ filter(Post.topic_id == Topic.id).\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == current_user.id)).\ add_entity(TopicsRead).\ order_by(Post.id.desc()).\ paginate(page, current_app.config['TOPICS_PER_PAGE'], True) else: forum = Forum.query.filter(Forum.id == forum_id).first_or_404() forum = (forum, None) topics = Topic.query.filter_by(forum_id=forum[0].id).\ filter(Post.topic_id == Topic.id).\ order_by(Post.id.desc()).\ paginate(page, current_app.config['TOPICS_PER_PAGE'], True, True) return render_template("forum/forum.html", forum=forum, topics=topics)
def update_read(self, user, forumsread, topicsread): """Updates the ForumsRead status for the user. In order to work correctly, be sure that `topicsread is **not** `None`. :param user: The user for whom we should check if he has read the forum. :param forumsread: The forumsread object. It is needed to check if if the forum is unread. If `forumsread` is `None` and the forum is unread, it will create a new entry in the `ForumsRead` relation, else (and the forum is still unread) we are just going to update the entry in the `ForumsRead` relation. :param topicsread: The topicsread object is used in combination with the forumsread object to check if the forumsread relation should be updated and therefore is unread. """ if not user.is_authenticated() or topicsread is None: return False # fetch the unread posts in the forum unread_count = Topic.query.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Topic.forum_id, ForumsRead.user_id == user.id)).\ filter(Topic.forum_id == self.id, db.or_(TopicsRead.last_read == None, TopicsRead.last_read < Topic.last_updated)).\ count() # No unread topics available - trying to mark the forum as read if unread_count == 0: if forumsread and forumsread.last_read > topicsread.last_read: return False # ForumRead Entry exists - Updating it because a new topic/post # has been submitted and has read everything (obviously, else the # unread_count would be useless). elif forumsread: forumsread.last_read = datetime.utcnow() forumsread.save() return True # No ForumRead Entry existing - creating one. forumsread = ForumsRead() forumsread.user_id = user.id forumsread.forum_id = self.id forumsread.last_read = datetime.utcnow() forumsread.save() return True # Nothing updated, because there are still more than 0 unread topics return False
def get_all(cls, user): """Get all categories with all associated forums. It returns a list with tuples. Those tuples are containing the category and their associated forums (whose are stored in a list). For example:: [(<Category 1>, [(<Forum 2>, <ForumsRead>), (<Forum 1>, None)]), (<Category 2>, [(<Forum 3>, None), (<Forum 4>, None)])] :param user: The user object is needed to check if we also need their forumsread object. """ if user.is_authenticated(): forums = cls.query.\ join(Forum, cls.id == Forum.category_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == user.id)).\ add_entity(Forum).\ add_entity(ForumsRead).\ order_by(Category.position, Category.id, Forum.position).\ all() else: # Get all the forums forums = cls.query.\ join(Forum, cls.id == Forum.category_id).\ add_entity(Forum).\ order_by(Category.position, Category.id, Forum.position).\ all() return get_categories_and_forums(forums, user)
def get_topics(cls, forum_id, user, page=1, per_page=20): """Get the topics for the forum. If the user is logged in, it will perform an outerjoin for the topics with the topicsread and forumsread relation to check if it is read or unread. :param forum_id: The forum id :param user: The user object :param page: The page whom should be loaded :param per_page: How many topics per page should be shown """ if user.is_authenticated(): topics = Topic.query.filter_by(forum_id=forum_id).\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ add_entity(TopicsRead).\ order_by(Topic.important.desc(), Topic.last_updated.desc()).\ paginate(page, per_page, True) else: topics = Topic.query.filter_by(forum_id=forum_id).\ order_by(Topic.important.desc(), Topic.last_updated.desc()).\ paginate(page, per_page, True) topics.items = [(topic, None) for topic in topics.items] return topics
def post(self, slug=None, plugin=None): form, old_settings, plugin_obj, active_nav = \ self._determine_active_settings(slug, plugin) all_groups = SettingsGroup.query.all() all_plugins = PluginRegistry.query.filter(db.and_( PluginRegistry.values != None, PluginRegistry.enabled == True )).all() if form.validate_on_submit(): new_settings = populate_settings_dict(form, old_settings) if plugin_obj is not None: plugin_obj.update_settings(new_settings) else: Setting.update(settings=new_settings, app=current_app) flash(_("Settings saved."), "success") return render_template( "management/settings.html", form=form, all_groups=all_groups, all_plugins=all_plugins, active_nav=active_nav )
def view_category(category_id, slug=None): if current_user.is_authenticated(): forum_query = Category.query.\ filter(Category.id == category_id).\ join(Forum, Category.id == Forum.category_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == 1)).\ add_entity(Forum).\ add_entity(ForumsRead).\ order_by(Forum.position).\ all() else: # we do not need to join the ForumsRead because the user isn't # signed in forum_query = Category.query.\ filter(Category.id == category_id).\ join(Forum, Category.id == Forum.category_id).\ add_entity(Forum).\ order_by(Forum.position).\ all() forum_query = [(category, forum, None) for category, forum in forum_query] category = get_forums(forum_query) return render_template("forum/category.html", categories=category)
def get(self, user_id): user = User.query.filter_by(id=user_id).first_or_404() form = self.form(user) member_group = db.and_( * [ db.not_(getattr(Group, p)) for p in ['admin', 'mod', 'super_mod', 'banned', 'guest'] ] ) filt = db.or_( Group.id.in_(g.id for g in current_user.groups), member_group ) if Permission(IsAtleastSuperModerator, identity=current_user): filt = db.or_(filt, Group.mod) if Permission(IsAdmin, identity=current_user): filt = db.or_(filt, Group.admin, Group.super_mod) if Permission(CanBanUser, identity=current_user): filt = db.or_(filt, Group.banned) group_query = Group.query.filter(filt) form.primary_group.query = group_query form.secondary_groups.query = group_query return render_template( 'management/user_form.html', form=form, title=_('Edit User') )
def validate_username(self, field): if hasattr(self, "user"): user = User.query.filter(db.and_(User.username.like(field.data), db.not_(User.id == self.user.id))).first() else: user = User.query.filter(User.username.like(field.data)).first() if user: raise ValidationError(_("This Username is already taken."))
def validate_name(self, field): if hasattr(self, "group"): group = Group.query.filter(db.and_(Group.name.like(field.data), db.not_(Group.id == self.group.id))).first() else: group = Group.query.filter(Group.name.like(field.data)).first() if group: raise ValidationError(_("This Group name is already taken."))
def validate_guest(self, field): if hasattr(self, "group"): group = Group.query.filter(db.and_(Group.guest, db.not_(Group.id == self.group.id))).count() else: group = Group.query.filter_by(guest=True).count() if field.data and group > 0: raise ValidationError(_("There is already a Guest group."))
def get_all(cls, user): """Get all categories with all associated forums. It returns a list with tuples. Those tuples are containing the category and their associated forums (whose are stored in a list). For example:: [(<Category 1>, [(<Forum 2>, <ForumsRead>), (<Forum 1>, None)]), (<Category 2>, [(<Forum 3>, None), (<Forum 4>, None)])] :param user: The user object is needed to check if we also need their forumsread object. """ # import Group model locally to avoid cicular imports from flaskbb.user.models import Group if user.is_authenticated(): # get list of user group ids user_groups = [gr.id for gr in user.groups] # filter forums by user groups user_forums = Forum.query.filter(Forum.groups.any( Group.id.in_(user_groups)) ).subquery() forum_alias = aliased(Forum, user_forums) # get all forums = cls.query.join( forum_alias, cls.id == forum_alias.category_id ).outerjoin( ForumsRead, db.and_( ForumsRead.forum_id == forum_alias.id, ForumsRead.user_id == user.id ) ).add_entity( forum_alias ).add_entity( ForumsRead ).order_by( Category.position, Category.id, forum_alias.position ).all() else: guest_group = Group.get_guest_group() # filter forums by guest groups guest_forums = Forum.query.filter( Forum.groups.any(Group.id==guest_group.id) ).subquery() forum_alias = aliased(Forum, guest_forums) forums = cls.query.join( forum_alias, cls.id == forum_alias.category_id ).add_entity( forum_alias ).order_by( Category.position, Category.id, forum_alias.position ).all() return get_categories_and_forums(forums, user)
def view_forum(forum_id): page = request.args.get('page', 1, type=int) if current_user.is_authenticated(): forum = Forum.query.\ filter(Forum.id == forum_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == current_user.id)).\ add_entity(ForumsRead).\ first_or_404() subforums = Forum.query.\ filter(Forum.parent_id == forum[0].id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == current_user.id)).\ add_entity(ForumsRead).\ all() topics = Topic.query.filter_by(forum_id=forum[0].id).\ filter(Post.topic_id == Topic.id).\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == current_user.id)).\ add_entity(TopicsRead).\ order_by(Post.id.desc()).\ paginate(page, current_app.config['TOPICS_PER_PAGE'], True) else: forum = Forum.query.filter(Forum.id == forum_id).first_or_404() forum = (forum, None) subforums = Forum.query.filter(Forum.parent_id == forum[0].id).all() # This isn't really nice imho, but "add_entity" (see above) # makes a list with tuples subforums = [(item, None) for item in subforums] topics = Topic.query.filter_by(forum_id=forum[0].id).\ filter(Post.topic_id == Topic.id).\ order_by(Post.id.desc()).\ paginate(page, current_app.config['TOPICS_PER_PAGE'], True, True) return render_template("forum/forum.html", forum=forum, topics=topics, subforums=subforums)
def topictracker(): page = request.args.get("page", 1, type=int) topics = current_user.tracked_topics.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == current_user.id)).\ add_entity(TopicsRead).\ order_by(Post.id.desc()).\ paginate(page, flaskbb_config['TOPICS_PER_PAGE'], True) return render_template("forum/topictracker.html", topics=topics)
def validate_banned(self, field): if hasattr(self, "group"): group = Group.query.filter( db.and_(Group.banned == True, db.not_(Group.id == self.group.id) ) ).count() else: group = Group.query.filter_by(banned=True).count() if field.data and group > 0: raise ValidationError("There is already a Banned group")
def validate_email(self, field): if hasattr(self, "user"): user = User.query.filter( db.and_(User.email.like(field.data), db.not_(User.id == self.user.id) ) ).first() else: user = User.query.filter(User.email.like(field.data)).first() if user: raise ValidationError("This email is taken")
def get_forums(cls, category_id, user): """Get the forums for the category. It returns a tuple with the category and the forums with their forumsread object are stored in a list. A return value can look like this for a category with two forums:: (<Category 1>, [(<Forum 1>, None), (<Forum 2>, None)]) :param category_id: The category id :param user: The user object is needed to check if we also need their forumsread object. """ from flaskbb.user.models import Group if user.is_authenticated: # get list of user group ids user_groups = [gr.id for gr in user.groups] # filter forums by user groups user_forums = Forum.query.\ filter(Forum.groups.any(Group.id.in_(user_groups))).\ subquery() forum_alias = aliased(Forum, user_forums) forums = cls.query.\ filter(cls.id == category_id).\ join(forum_alias, cls.id == forum_alias.category_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == forum_alias.id, ForumsRead.user_id == user.id)).\ add_entity(forum_alias).\ add_entity(ForumsRead).\ order_by(forum_alias.position).\ all() else: guest_group = Group.get_guest_group() # filter forums by guest groups guest_forums = Forum.query.\ filter(Forum.groups.any(Group.id == guest_group.id)).\ subquery() forum_alias = aliased(Forum, guest_forums) forums = cls.query.\ filter(cls.id == category_id).\ join(forum_alias, cls.id == forum_alias.category_id).\ add_entity(forum_alias).\ order_by(forum_alias.position).\ all() if not forums: abort(404) return get_forums(forums, user)
def validate_email(self, field): if hasattr(self, "user"): user = User.query.filter( db.and_( User.email.like(field.data), db.not_(User.id == self.user.id) ) ).first() else: user = User.query.filter(User.email.like(field.data)).first() if user: raise ValidationError(_("This E-Mail Address is already taken."))
def validate_name(self, field): if hasattr(self, "group"): group = Group.query.filter( db.and_( Group.name.like(field.data), db.not_(Group.id == self.group.id) ) ).first() else: group = Group.query.filter(Group.name.like(field.data)).first() if group: raise ValidationError(_("This Group name is already taken."))
def validate_banned(self, field): if hasattr(self, "group"): group = Group.query.filter( db.and_( Group.banned, db.not_(Group.id == self.group.id) ) ).count() else: group = Group.query.filter_by(banned=True).count() if field.data and group > 0: raise ValidationError(_("There is already a Banned group."))
def index(): # Get the categories and forums if current_user.is_authenticated(): forum_query = Category.query.\ join(Forum, Category.id == Forum.category_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == current_user.id)).\ add_entity(Forum).\ add_entity(ForumsRead).\ order_by(Category.id, Category.position, Forum.position).\ all() else: # we do not need to join the ForumsRead because the user isn't # signed in forum_query = Category.query.\ join(Forum, Category.id == Forum.category_id).\ add_entity(Forum).\ order_by(Category.id, Category.position, Forum.position).\ all() forum_query = [(category, forum, None) for category, forum in forum_query] categories = get_forums(forum_query) # Fetch a few stats about the forum user_count = User.query.count() topic_count = Topic.query.count() post_count = Post.query.count() newest_user = User.query.order_by(User.id.desc()).first() # Check if we use redis or not if not current_app.config["REDIS_ENABLED"]: online_users = User.query.filter(User.lastseen >= time_diff()).count() # Because we do not have server side sessions, we cannot check if there # are online guests online_guests = None else: online_users = len(get_online_users()) online_guests = len(get_online_users(guest=True)) return render_template("forum/index.html", categories=categories, user_count=user_count, topic_count=topic_count, post_count=post_count, newest_user=newest_user, online_users=online_users, online_guests=online_guests)
def get_all(cls, user): """Get all categories with all associated forums. It returns a list with tuples. Those tuples are containing the category and their associated forums (whose are stored in a list). For example:: [(<Category 1>, [(<Forum 2>, <ForumsRead>), (<Forum 1>, None)]), (<Category 2>, [(<Forum 3>, None), (<Forum 4>, None)])] :param user: The user object is needed to check if we also need their forumsread object. """ # import Group model locally to avoid cicular imports from flaskbb.user.models import Group if user.is_authenticated: # get list of user group ids user_groups = [gr.id for gr in user.groups] # filter forums by user groups user_forums = Forum.query.\ filter(Forum.groups.any(Group.id.in_(user_groups))).\ subquery() forum_alias = aliased(Forum, user_forums) # get all forums = cls.query.\ join(forum_alias, cls.id == forum_alias.category_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == forum_alias.id, ForumsRead.user_id == user.id)).\ add_entity(forum_alias).\ add_entity(ForumsRead).\ order_by(Category.position, Category.id, forum_alias.position).\ all() else: guest_group = Group.get_guest_group() # filter forums by guest groups guest_forums = Forum.query.\ filter(Forum.groups.any(Group.id == guest_group.id)).\ subquery() forum_alias = aliased(Forum, guest_forums) forums = cls.query.\ join(forum_alias, cls.id == forum_alias.category_id).\ add_entity(forum_alias).\ order_by(Category.position, Category.id, forum_alias.position).\ all() return get_categories_and_forums(forums, user)
def validate_guest(self, field): if hasattr(self, "group"): group = Group.query.filter( db.and_( Group.guest, db.not_(Group.id == self.group.id) ) ).count() else: group = Group.query.filter_by(guest=True).count() if field.data and group > 0: raise ValidationError(_("There is already a group of type " "'Guest'."))
def validate_username(self, field): if hasattr(self, "user"): user = User.query.filter( db.and_( User.username.like(field.data.lower()), db.not_(User.id == self.user.id) ) ).first() else: user = User.query.filter( User.username.like(field.data.lower()) ).first() if user: raise ValidationError(_("This username is already taken."))
def validate_email(self, field): if hasattr(self, "user"): user = User.query.filter( db.and_( User.email.like(field.data.lower()), db.not_(User.id == self.user.id) ) ).first() else: user = User.query.filter( User.email.like(field.data.lower()) ).first() if user: raise ValidationError(_("This email address is already taken."))
def get(self): page = request.args.get("page", 1, type=int) topics = real(current_user).tracked_topics.\ outerjoin( TopicsRead, db.and_( TopicsRead.topic_id == Topic.id, TopicsRead.user_id == real(current_user).id )).\ outerjoin(Post, Topic.last_post_id == Post.id).\ outerjoin(Forum, Topic.forum_id == Forum.id).\ outerjoin( ForumsRead, db.and_( ForumsRead.forum_id == Forum.id, ForumsRead.user_id == real(current_user).id )).\ add_entity(Post).\ add_entity(TopicsRead).\ add_entity(ForumsRead).\ order_by(Topic.last_updated.desc()).\ paginate(page, flaskbb_config["TOPICS_PER_PAGE"], True) return render_template("forum/topictracker.html", topics=topics)
def get(self, slug=None, plugin=None): form, old_settings, plugin_obj, active_nav = \ self._determine_active_settings(slug, plugin) # get all groups and plugins - used to build the navigation all_groups = SettingsGroup.query.all() all_plugins = PluginRegistry.query.filter( db.and_(PluginRegistry.values != None, PluginRegistry.enabled == True)).all() form = populate_settings_form(form, old_settings) return render_template("management/settings.html", form=form, all_groups=all_groups, all_plugins=all_plugins, active_nav=active_nav)
def edit_user(user_id): user = User.query.filter_by(id=user_id).first_or_404() if not Permission(CanEditUser, identity=current_user): flash(_("You are not allowed to edit this user."), "danger") return redirect(url_for("management.users")) member_group = db.and_(*[ db.not_(getattr(Group, p)) for p in ['admin', 'mod', 'super_mod', 'banned', 'guest'] ]) filt = db.or_(Group.id.in_(g.id for g in current_user.groups), member_group) if Permission(IsAtleastSuperModerator, identity=current_user): filt = db.or_(filt, Group.mod) if Permission(IsAdmin, identity=current_user): filt = db.or_(filt, Group.admin, Group.super_mod) if Permission(CanBanUser, identity=current_user): filt = db.or_(filt, Group.banned) group_query = Group.query.filter(filt) form = EditUserForm(user) form.primary_group.query = group_query form.secondary_groups.query = group_query if form.validate_on_submit(): form.populate_obj(user) user.primary_group_id = form.primary_group.data.id # Don't override the password if form.password.data: user.password = form.password.data user.save(groups=form.secondary_groups.data) flash(_("User updated."), "success") return redirect(url_for("management.edit_user", user_id=user.id)) return render_template("management/user_form.html", form=form, title=_("Edit User"))
def post(self, user_id): user = User.query.filter_by(id=user_id).first_or_404() member_group = db.and_( * [ db.not_(getattr(Group, p)) for p in ['admin', 'mod', 'super_mod', 'banned', 'guest'] ] ) filt = db.or_( Group.id.in_(g.id for g in current_user.groups), member_group ) if Permission(IsAtleastSuperModerator, identity=current_user): filt = db.or_(filt, Group.mod) if Permission(IsAdmin, identity=current_user): filt = db.or_(filt, Group.admin, Group.super_mod) if Permission(CanBanUser, identity=current_user): filt = db.or_(filt, Group.banned) group_query = Group.query.filter(filt) form = EditUserForm(user) form.primary_group.query = group_query form.secondary_groups.query = group_query if form.validate_on_submit(): form.populate_obj(user) user.primary_group_id = form.primary_group.data.id # Don't override the password if form.password.data: user.password = form.password.data user.save(groups=form.secondary_groups.data) flash(_('User updated.'), 'success') return redirect(url_for('management.edit_user', user_id=user.id)) return render_template( 'management/user_form.html', form=form, title=_('Edit User') )
def get_forums(cls, category_id, user): """Get the forums for the category. It returns a tuple with the category and the forums with their forumsread object are stored in a list. A return value can look like this for a category with two forums:: (<Category 1>, [(<Forum 1>, None), (<Forum 2>, None)]) :param category_id: The category id :param user: The user object is needed to check if we also need their forumsread object. """ from flaskbb.user.models import Group if user.is_authenticated(): # get list of user group ids user_groups = [gr.id for gr in user.groups] # filter forums by user groups user_forums = Forum.query.filter( Forum.groups.any(Group.id.in_(user_groups))).subquery() forum_alias = aliased(Forum, user_forums) forums = cls.query.filter(cls.id == category_id).join( forum_alias, cls.id == forum_alias.category_id).outerjoin( ForumsRead, db.and_(ForumsRead.forum_id == forum_alias.id, ForumsRead.user_id == user.id)).add_entity( forum_alias).add_entity(ForumsRead).order_by( forum_alias.position).all() else: guest_group = Group.get_guest_group() # filter forums by guest groups guest_forums = Forum.query.filter( Forum.groups.any(Group.id == guest_group.id)).subquery() forum_alias = aliased(Forum, guest_forums) forums = cls.query.filter(cls.id == category_id).join( forum_alias, cls.id == forum_alias.category_id).add_entity( forum_alias).order_by(forum_alias.position).all() if not forums: abort(404) return get_forums(forums, user)
def get(self, slug=None, plugin=None): form, old_settings, plugin_obj, active_nav = \ self._determine_active_settings(slug, plugin) # get all groups and plugins - used to build the navigation all_groups = SettingsGroup.query.all() all_plugins = PluginRegistry.query.filter(db.and_( PluginRegistry.values != None, PluginRegistry.enabled == True )).all() form = populate_settings_form(form, old_settings) return render_template( "management/settings.html", form=form, all_groups=all_groups, all_plugins=all_plugins, active_nav=active_nav )
def edit_user(user_id): user = User.query.filter_by(id=user_id).first_or_404() if not can_edit_user(current_user): flash(_("You are not allowed to edit this user."), "danger") return redirect(url_for("management.users")) member_group = db.and_(*[db.not_(getattr(Group, p)) for p in ['admin', 'mod', 'super_mod', 'banned', 'guest' ]]) filt = db.or_(Group.id.in_(g.id for g in user.groups), member_group) if any(user.permissions[p] for p in ['super_mod', 'admin']): filt = db.or_(filt, Group.mod) if user.permissions['admin']: filt = db.or_(filt, Group.admin, Group.super_mod) group_query = Group.query.filter(filt) form = EditUserForm(user) form.primary_group.query = group_query form.secondary_groups.query = group_query if form.validate_on_submit(): form.populate_obj(user) user.primary_group_id = form.primary_group.data.id # Don't override the password if form.password.data: user.password = form.password.data user.save(groups=form.secondary_groups.data) flash(_("User successfully updated."), "success") return redirect(url_for("management.edit_user", user_id=user.id)) return render_template("management/user_form.html", form=form, title=_("Edit User"))
def get_forum(cls, forum_id, user): """Returns the forum and forumsread object as a tuple for the user. :param forum_id: The forum id :param user: The user object is needed to check if we also need their forumsread object. """ if user.is_authenticated: forum, forumsread = Forum.query.\ filter(Forum.id == forum_id).\ options(db.joinedload("category")).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == user.id)).\ add_entity(ForumsRead).\ first_or_404() else: forum = Forum.query.filter(Forum.id == forum_id).first_or_404() forumsread = None return forum, forumsread
def post(self, slug=None, plugin=None): form, old_settings, plugin_obj, active_nav = \ self._determine_active_settings(slug, plugin) all_groups = SettingsGroup.query.all() all_plugins = PluginRegistry.query.filter( db.and_(PluginRegistry.values != None, PluginRegistry.enabled == True)).all() if form.validate_on_submit(): new_settings = populate_settings_dict(form, old_settings) if plugin_obj is not None: plugin_obj.update_settings(new_settings) else: Setting.update(settings=new_settings, app=current_app) flash(_("Settings saved."), "success") return render_template("management/settings.html", form=form, all_groups=all_groups, all_plugins=all_plugins, active_nav=active_nav)
def index(): # Get the categories and forums if current_user.is_authenticated(): categories_query = Forum.query.\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == current_user.id)).\ add_entity(ForumsRead).\ order_by(Forum.position.asc()).\ all() categories = get_forums(categories_query, current_user=True) else: categories_query = Forum.query.order_by(Forum.position.asc()).all() categories = get_forums(categories_query, current_user=False) # Fetch a few stats about the forum user_count = User.query.count() topic_count = Topic.query.count() post_count = Post.query.count() newest_user = User.query.order_by(User.id.desc()).first() # Check if we use redis or not if not current_app.config["REDIS_ENABLED"]: online_users = User.query.filter(User.lastseen >= time_diff()).count() online_guests = None else: online_users = len(get_online_users()) online_guests = len(get_online_users(guest=True)) return render_template("forum/index.html", categories=categories, user_count=user_count, topic_count=topic_count, post_count=post_count, newest_user=newest_user, online_users=online_users, online_guests=online_guests)
def get_forums(cls, category_id, user): """Get the forums for the category. It returns a tuple with the category and the forums with their forumsread object are stored in a list. A return value can look like this for a category with two forums:: (<Category 1>, [(<Forum 1>, None), (<Forum 2>, None)]) :param category_id: The category id :param user: The user object is needed to check if we also need their forumsread object. """ if user.is_authenticated(): forums = cls.query.\ filter(cls.id == category_id).\ join(Forum, cls.id == Forum.category_id).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Forum.id, ForumsRead.user_id == user.id)).\ add_entity(Forum).\ add_entity(ForumsRead).\ order_by(Forum.position).\ all() else: forums = cls.query.\ filter(cls.id == category_id).\ join(Forum, cls.id == Forum.category_id).\ add_entity(Forum).\ order_by(Forum.position).\ all() if not forums: abort(404) return get_forums(forums, user)
def topictracker(): page = request.args.get("page", 1, type=int) topics = current_user.tracked_topics.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == current_user.id)).\ add_entity(TopicsRead).\ order_by(Topic.last_updated.desc()).\ paginate(page, flaskbb_config['TOPICS_PER_PAGE'], True) # bulk untracking if request.method == "POST": topic_ids = request.form.getlist("rowid") tmp_topics = Topic.query.filter(Topic.id.in_(topic_ids)).all() for topic in tmp_topics: current_user.untrack_topic(topic) current_user.save() flash(_("%(topic_count)s topics untracked.", topic_count=len(tmp_topics)), "success") return redirect(url_for("forum.topictracker")) return render_template("forum/topictracker.html", topics=topics)
def get_topics(cls, forum_id, user, page=1, per_page=20): """Get the topics for the forum. If the user is logged in, it will perform an outerjoin for the topics with the topicsread and forumsread relation to check if it is read or unread. :param forum_id: The forum id :param user: The user object :param page: The page whom should be loaded :param per_page: How many topics per page should be shown """ if user.is_authenticated: # Now thats intersting - if i don't do the add_entity(Post) # the n+1 still exists when trying to access 'topic.last_post' # but without it it will fire another query. # This way I don't have to use the last_post object when I # iterate over the result set. topics = Topic.query.filter_by(forum_id=forum_id).\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ outerjoin(Post, Topic.last_post_id == Post.id).\ add_entity(Post).\ add_entity(TopicsRead).\ order_by(Topic.important.desc(), Topic.last_updated.desc()).\ paginate(page, per_page, True) else: topics = Topic.query.filter_by(forum_id=forum_id).\ outerjoin(Post, Topic.last_post_id == Post.id).\ add_entity(Post).\ order_by(Topic.important.desc(), Topic.last_updated.desc()).\ paginate(page, per_page, True) topics.items = [(topic, last_post, None) for topic, last_post, in topics.items] return topics
def update_read(self, user, forumsread, topicsread): """Updates the ForumsRead status for the user. In order to work correctly, be sure that `topicsread is **not** `None`. :param user: The user for whom we should check if he has read the forum. :param forumsread: The forumsread object. It is needed to check if if the forum is unread. If `forumsread` is `None` and the forum is unread, it will create a new entry in the `ForumsRead` relation, else (and the forum is still unread) we are just going to update the entry in the `ForumsRead` relation. :param topicsread: The topicsread object is used in combination with the forumsread object to check if the forumsread relation should be updated and therefore is unread. """ if not user.is_authenticated or topicsread is None: return False read_cutoff = None if flaskbb_config['TRACKER_LENGTH'] > 0: read_cutoff = time_utcnow() - timedelta( days=flaskbb_config['TRACKER_LENGTH']) # fetch the unread posts in the forum unread_count = Topic.query.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Topic.forum_id, ForumsRead.user_id == user.id)).\ filter(Topic.forum_id == self.id, Topic.last_updated > read_cutoff, db.or_(TopicsRead.last_read == None, # noqa: E711 TopicsRead.last_read < Topic.last_updated), db.or_(ForumsRead.last_read == None, # noqa: E711 ForumsRead.last_read < Topic.last_updated)).\ count() # No unread topics available - trying to mark the forum as read if unread_count == 0: logger.debug("No unread topics. Trying to mark the forum as read.") if forumsread and forumsread.last_read > topicsread.last_read: logger.debug("forumsread.last_read is newer than " "topicsread.last_read. Everything is read.") return False # ForumRead Entry exists - Updating it because a new topic/post # has been submitted and has read everything (obviously, else the # unread_count would be useless). elif forumsread: logger.debug("Updating existing ForumsRead '{}' object." .format(forumsread)) forumsread.last_read = time_utcnow() forumsread.save() return True # No ForumRead Entry existing - creating one. logger.debug("Creating new ForumsRead object.") forumsread = ForumsRead() forumsread.user = user forumsread.forum = self forumsread.last_read = time_utcnow() forumsread.save() return True # Nothing updated, because there are still more than 0 unread # topicsread logger.debug("No ForumsRead object updated - there are still {} " "unread topics.".format(unread_count)) return False
def update_read(self, user, forumsread, topicsread): """Updates the ForumsRead status for the user. In order to work correctly, be sure that `topicsread is **not** `None`. :param user: The user for whom we should check if he has read the forum. :param forumsread: The forumsread object. It is needed to check if if the forum is unread. If `forumsread` is `None` and the forum is unread, it will create a new entry in the `ForumsRead` relation, else (and the forum is still unread) we are just going to update the entry in the `ForumsRead` relation. :param topicsread: The topicsread object is used in combination with the forumsread object to check if the forumsread relation should be updated and therefore is unread. """ if not user.is_authenticated or topicsread is None: return False read_cutoff = None if flaskbb_config['TRACKER_LENGTH'] > 0: read_cutoff = time_utcnow() - timedelta( days=flaskbb_config['TRACKER_LENGTH']) # fetch the unread posts in the forum unread_count = Topic.query.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Topic.forum_id, ForumsRead.user_id == user.id)).\ filter(Topic.forum_id == self.id, Topic.last_updated > read_cutoff, db.or_(TopicsRead.last_read == None, TopicsRead.last_read < Topic.last_updated)).\ count() # No unread topics available - trying to mark the forum as read if unread_count == 0: if forumsread and forumsread.last_read > topicsread.last_read: return False # ForumRead Entry exists - Updating it because a new topic/post # has been submitted and has read everything (obviously, else the # unread_count would be useless). elif forumsread: forumsread.last_read = time_utcnow() forumsread.save() return True # No ForumRead Entry existing - creating one. forumsread = ForumsRead() forumsread.user_id = user.id forumsread.forum_id = self.id forumsread.last_read = time_utcnow() forumsread.save() return True # Nothing updated, because there are still more than 0 unread # topicsread return False
def validate_email(self, field): user = User.query.filter(db.and_( User.email.like(field.data), db.not_(User.id == self.user.id))).first() if user: raise ValidationError(_("This E-Mail Address is already taken."))
def validate_email(self, field): user = User.query.filter( db.and_(User.email.like(field.data), db.not_(User.id == self.user.id))).first() if user: raise ValidationError("This email is taken")
def update_read(self, user, forum, forumsread=None): """Update the topics read status if the user hasn't read the latest post. :param user: The user for whom the readstracker should be updated :param forum: The forum in which the topic is :param forumsread: The forumsread object. It is used to check if there is a new post since the forum has been marked as read """ read_cutoff = datetime.utcnow() - timedelta( days=current_app.config['TRACKER_LENGTH']) # Anonymous User or the post is too old for inserting it in the # TopicsRead model if not user.is_authenticated() or \ read_cutoff > self.last_post.date_created: return topicread = TopicsRead.query.\ filter(TopicsRead.user_id == user.id, TopicsRead.topic_id == self.id).first() # Can be None if the user has never marked the forum as read. If this # condition is false - we need to update the tracker if forumsread and forumsread.cleared is not None and \ forumsread.cleared >= self.last_post.date_created: return # A new post has been submitted that the user hasn't read. # Updating... if topicread and (topicread.last_read < self.last_post.date_created): topicread.last_read = datetime.utcnow() topicread.save() # The user has not visited the topic before. Inserting him in # the TopicsRead model. elif not topicread: topicread = TopicsRead() topicread.user_id = user.id topicread.topic_id = self.id topicread.forum_id = self.forum_id topicread.last_read = datetime.utcnow() topicread.save() # else: no unread posts if forum: # fetch the unread posts in the forum unread_count = Topic.query.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Topic.forum_id, ForumsRead.user_id == user.id)).\ filter(Topic.forum_id == forum.id, db.or_(TopicsRead.last_read == None, TopicsRead.last_read < Topic.last_updated)).\ count() #No unread topics available - trying to mark the forum as read if unread_count == 0: forumread = ForumsRead.query.\ filter(ForumsRead.user_id == user.id, ForumsRead.forum_id == forum.id).first() # ForumsRead is already up-to-date. if forumread and forumread.last_read > topicread.last_read: return # ForumRead Entry exists - Updating it because a new post # has been submitted that the user hasn't read. elif forumread: forumread.last_read = datetime.utcnow() forumread.save() # No ForumRead Entry existing - creating one. else: forumread = ForumsRead() forumread.user_id = user.id forumread.forum_id = forum.id forumread.last_read = datetime.utcnow() forumread.save()
def update_read(self, user, forum, forumsread=None): """Update the topics read status if the user hasn't read the latest post. :param user: The user for whom the readstracker should be updated :param forum: The forum in which the topic is :param forumsread: The forumsread object. It is used to check if there is a new post since the forum has been marked as read """ read_cutoff = datetime.utcnow() - timedelta( days=current_app.config['TRACKER_LENGTH']) # Anonymous User or the post is too old for inserting it in the # TopicsRead model if not user.is_authenticated() or \ read_cutoff > self.last_post.date_created: return topicread = TopicsRead.query.\ filter(TopicsRead.user_id == user.id, TopicsRead.topic_id == self.id).first() # Can be None if the user has never marked the forum as read. If this # condition is false - we need to update the tracker if forumsread and forumsread.cleared is not None and \ forumsread.cleared >= self.last_post.date_created: return # A new post has been submitted that the user hasn't read. # Updating... if topicread and (topicread.last_read < self.last_post.date_created): topicread.last_read = datetime.utcnow() topicread.save() # The user has not visited the topic before. Inserting him in # the TopicsRead model. elif not topicread: topicread = TopicsRead() topicread.user_id = user.id topicread.topic_id = self.id topicread.forum_id = self.forum_id topicread.last_read = datetime.utcnow() topicread.save() # else: no unread posts if forum: # fetch the unread posts in the forum unread_count = Topic.query.\ outerjoin(TopicsRead, db.and_(TopicsRead.topic_id == Topic.id, TopicsRead.user_id == user.id)).\ outerjoin(ForumsRead, db.and_(ForumsRead.forum_id == Topic.forum_id, ForumsRead.user_id == user.id)).\ filter(Topic.forum_id == forum.id, db.or_(TopicsRead.last_read == None, TopicsRead.last_read < Topic.last_updated)).\ count() # No unread topics available - trying to mark the forum as read if unread_count == 0: forumread = ForumsRead.query.\ filter(ForumsRead.user_id == user.id, ForumsRead.forum_id == forum.id).first() # ForumsRead is already up-to-date. if forumread and forumread.last_read > topicread.last_read: return # ForumRead Entry exists - Updating it because a new post # has been submitted that the user hasn't read. elif forumread: forumread.last_read = datetime.utcnow() forumread.save() # No ForumRead Entry existing - creating one. else: forumread = ForumsRead() forumread.user_id = user.id forumread.forum_id = forum.id forumread.last_read = datetime.utcnow() forumread.save()