def create(): user: User = get_user_from_app_context() attrs = request.json attrs["author_id"] = user._id q = Question(attrs) q.save() return json_response({"data": q.api_dict(fields=QUESTION_FIELDS)})
def users_subscription(): user: User = get_user_from_app_context() us = user.user_subscription users = [] for user in us.subscribed_to: users.append(user.to_dict(fields=USER_FIELDS)) return json_response({"data": users})
def dismiss(event_id): user: User = get_user_from_app_context() event = Event.get(event_id, "event not found") if event.user_id != user._id: raise NotFound("event not found") if not event.dismissed: event.dismiss() return json_response({"data": event.api_dict()})
def my_vote(self) -> int: if not has_request_context(): return 0 u = get_user_from_app_context() if u is None: return 0 v = Vote.find_one({"post_id": self._id, "user_id": u._id}) return v.value if v is not None else 0
def dismiss_all(): user: User = get_user_from_app_context() Event.update_many({ "user_id": user._id, "dismissed": False }, {"$set": { "dismissed": True }}) return json_response({"status": "dismissed"})
def accept_answer(question_id, answer_id): u: User = get_user_from_app_context() q: Optional[Question] = Question.get(question_id, "answer not found") a: Optional[Answer] = Answer.get(answer_id, "answer not found") if a.parent_id != q._id: raise NotFound("answer not found") if q.author_id != u._id: raise Forbidden("only question's author can accept answers") q.set_accepted_answer(a) return json_response({"data": a.api_dict(ANSWER_FIELDS)})
def create_comment(question_id): q = Question.get(question_id, "question not found") user: User = get_user_from_app_context() attrs = request.json if "body" not in attrs: raise ApiError("body is missing") c = q.create_comment({"body": attrs["body"], "author_id": user._id}) c.save() return json_response({"data": c.api_dict(COMMENT_FIELDS)})
def create_answer(question_id): q: Optional[Question] = Question.get(question_id, "question not found") user: User = get_user_from_app_context() attrs = request.json if "body" not in attrs: raise ApiError("body is missing") a = q.create_answer({"author_id": user._id, "body": attrs["body"]}) a.save() return json_response({"data": a.api_dict()})
def tags_subscribe(): user: User = get_user_from_app_context() tags = request.json.get("tags") if tags is None: raise InputDataError("tags field is mandatory") tags = list(set(tags)) # make sure tags are unique ts = user.tag_subscription ts.tags = tags ts.save() json_response({"data": ts.to_dict(fields=TAG_SUBSCRIPTION_FIELDS)})
def revoke_answer(question_id, answer_id): u: User = get_user_from_app_context() q: Optional[Question] = Question.get(question_id, "answer not found") a: Optional[Answer] = Answer.get(answer_id, "answer not found") if a.parent_id != q._id: raise NotFound("answer not found") if q.author_id != u._id: raise Forbidden("only question's author can revoke answers") if not a.accepted: raise NotAccepted("answer is not accepted so can't be revoked") q.set_accepted_answer(None) a.reload() return json_response({"data": a.api_dict(ANSWER_FIELDS)})
def create_answer_comment(question_id, answer_id): a: Optional[Answer] = Answer.get(answer_id, "answer not found") if a.parent_id != resolve_id(question_id): raise NotFound("answer not found") user: User = get_user_from_app_context() attrs = request.json if "body" not in attrs: raise ApiError("body is missing") c = a.create_comment({"body": attrs["body"], "author_id": user._id}) c.save() return json_response({"data": c.api_dict(COMMENT_FIELDS)})
def vote_question(question_id): q: Optional[Question] = Question.get(question_id, "question not found") u: User = get_user_from_app_context() if q.author_id == u._id: raise Forbidden("you can't vote for your own question") attrs = request.json if "value" not in attrs: raise ApiError("value field is mandatory") Vote.vote(q._id, u._id, attrs["value"]) q.reload() return json_response({"data": q.api_dict(fields=QUESTION_FIELDS)})
def vote_answer(question_id, answer_id): a: Optional[Answer] = Answer.get(answer_id, "answer not found") if a.parent_id != resolve_id(question_id): raise NotFound("answer not found") u: User = get_user_from_app_context() if a.author_id == u._id: raise Forbidden("you can't vote for your own answers") attrs = request.json if "value" not in attrs: raise ApiError("value field is mandatory") Vote.vote(a._id, u._id, attrs["value"]) a.reload() return json_response({"data": a.api_dict(fields=ANSWER_FIELDS)})
def vote_comment(question_id, comment_id): c: Optional[Comment] = Comment.get(comment_id, "comment not found") if c.parent_id != resolve_id(question_id): raise NotFound("comment not found") u: User = get_user_from_app_context() if c.author_id == u._id: raise Forbidden("you can't vote for your own comments") attrs = request.json if "value" not in attrs: raise ApiError("value field is mandatory") Vote.vote(c._id, u._id, attrs["value"]) c.reload() return json_response({"data": c.api_dict(fields=COMMENT_FIELDS)})
def get(cls, expression, raise_if_none=None): post: Optional[BasePost] = super().get(expression, raise_if_none) if post and post.deleted: if has_request_context(): user: User = get_user_from_app_context() # if user logged in and he is moderator or post.author # he can view deleted post if not user or (user._id != post.author_id and not user.moderator): post = None if post is None and raise_if_none: if isinstance(raise_if_none, str): raise NotFound(raise_if_none) else: raise raise_if_none return post
def index(): u: User = get_user_from_app_context() if "_sort" in request.values: srt = request.values["_sort"] else: srt = "rating" sortExpr = SORT_MAP.get(srt) if sortExpr is None: raise ApiError(f"unknown sort operator \"{srt}\"") if get_boolean_request_param("_mine"): if u: # only mine posts query = {"author_id": u._id} else: # nothing to show, user is not logged in query = {"_id": NilObjectId} else: # otherwise show all not deleted posts query = { "$or": [ { "deleted": False }, ] } if u: # if user is logged in, he can view his own deleted posts query["$or"].append({"author_id": u._id}) questions = Question.find(query).sort(sortExpr) results = paginated( questions, transform=default_transform(fields=QUESTION_LIST_FIELDS)) author_ids = set() for q in results["data"]: author_ids.add(resolve_id(q["author_id"])) authors = User.find({"_id": {"$in": list(author_ids)}}) return json_response({"questions": results, "authors": {"data": authors}})
def update_allowed(self) -> bool: user: User = get_user_from_app_context() return self.author_id == user._id or user.moderator
def users_unsubscribe(user_id): current: User = get_user_from_app_context() user = User.get(user_id, "user not found") current.unsubscribe_from_user(user) return users_subscription()
def is_mine(self): if not has_request_context(): return True user = get_user_from_app_context() return user._id == self.author_id
def everything(self, user: Union['User', None] = None) -> Dict[str, Any]: if user is None: user = get_user_from_app_context() user_id = user._id if user else None qa_pipeline = [{ "$match": { "$or": [ { "_id": self._id }, { "parent_id": self._id, "submodel": "answer" }, ] } }, { "$sort": { "accepted": -1, "created_at": -1 }, }, { "$lookup": { "from": "votes", "let": { "post_id": "$_id" }, "pipeline": [{ "$match": { "$expr": { "$and": [{ "$eq": ["$post_id", "$$post_id"] }, { "$eq": ["$user_id", user_id] }] } } }, { "$project": { "_id": 0, "value": 1 } }], "as": "votes", } }] results = { "question": None, "answers": [], "comments": [], "authors": [] } author_ids = set() doc_ids = [] for doc in BasePost.aggregate(qa_pipeline): doc["my_vote"] = doc["votes"][0]["value"] if doc["votes"] else 0 del doc["votes"] doc_ids.append(doc["_id"]) if doc["submodel"] == "question": results["question"] = doc elif doc["submodel"] == "answer": if doc["deleted"]: # skip deleted answers unless user is the author or a moderator if user or (not user.moderator and user._id != doc["author_id"]): continue results["answers"].append(doc) author_ids.add(doc["author_id"]) c_pipeline = [{ "$match": { "parent_id": { "$in": doc_ids }, "submodel": "comment" }, }, { "$sort": { "created_at": 1 }, }, { "$lookup": { "from": "votes", "let": { "post_id": "$_id" }, "pipeline": [{ "$match": { "$expr": { "$and": [{ "$eq": ["$post_id", "$$post_id"] }, { "$eq": ["$user_id", user_id] }] } } }, { "$project": { "_id": 0, "value": 1 } }], "as": "votes", } }] for doc in BasePost.aggregate(c_pipeline): doc["my_vote"] = doc["votes"][0]["value"] if doc["votes"] else 0 del doc["votes"] if doc["deleted"]: # skip deleted answers unless user is the author or a moderator if not user or (not user.moderator and user._id != doc["author_id"]): continue results["comments"].append(doc) author_ids.add(doc["author_id"]) results["authors"] = (User.find({"_id": {"$in": list(author_ids)}})) return results
def delete_post(post): if not post.delete_allowed: raise Forbidden("you can't delete this post") user = get_user_from_app_context() post.delete_by(user)
def replace_subscription(): if "tags" not in request.json: raise ApiError("tags field is mandatory") user: User = get_user_from_app_context() user.replace_tags(request.json["tags"]) return json_response({"data": user.tag_subscription.to_dict()})
def me(): user = get_user_from_app_context() return json_response({ "data": account_dict(user), "providers": BaseProvider.list_provider_info() })
def update_settings(): user: User = get_user_from_app_context() user.update(request.json) return json_response({ "data": account_dict(user), })
def index(): user: User = get_user_from_app_context() events = user.get_new_events().sort("created_at", -1) return json_response( paginated(events, limit=5, transform=lambda event: event.api_dict()))
def wrapper(*args, **kwargs): u = get_user_from_app_context() if u is None: raise AuthenticationError() return func(*args, **kwargs)
def unsubscribe(tagname): Tag.get(tagname, "tag not found") user: User = get_user_from_app_context() user.unsubscribe_from_tag(tagname) return json_response({"data": user.tag_subscription.to_dict()})
def delete_allowed(self) -> bool: user: User = get_user_from_app_context() # print(user, user.moderator) return self.author_id == user._id or user.moderator
def restore_allowed(self) -> bool: user: User = get_user_from_app_context() return user._id == self.deleted_by_id
def update_post(post): if not post.update_allowed: raise Forbidden("you can't edit this post") attrs = request.json user = get_user_from_app_context() post.update_by(user, attrs)