Beispiel #1
0
    def on_accept_freq(data):
        freq = FriendshipRequest.query.filter_by(id=data["id"]).first()

        if freq.to_id == current_user.id:
            from_user = User.get_by_id(freq.from_id)

            new_friendship1 = Friendship(freq.from_id, freq.to_id)
            new_friendship2 = Friendship(freq.to_id, freq.from_id)
            db.session.add(new_friendship1)
            db.session.add(new_friendship2)

            emit("remove_friendship_request", data["id"], room=current_user.id)

            emit("new_friend",
                 {"id": from_user.id,
                  "name": from_user.name,
                  "unreadCount": 0,
                  "lastMsg": "None",
                  "picUrl": from_user.small_avatar_url,
                  "goToUrl": f"/{from_user.name}"},
                 room=current_user.id)

            emit("new_friend",
                 {"id": current_user.id,
                  "name": current_user.name,
                  "unreadCount": 0,
                  "lastMsg": "None",
                  "picUrl": current_user.small_avatar_url,
                  "goToUrl": f"/{current_user.name}"},
                 room=from_user.id)

            db.session.delete(freq)
            db.session.commit()
Beispiel #2
0
def msgs():
    if not current_user.is_authenticated():
        abort(404)

    chat_id = request.args.get("chat-id")
    chat_type = request.args.get("chat-type")

    if not chat_id or not chat_type:
        abort(400)

    msgs_in_chat = current_user.get_msgs_ordered_asc_by_datetime(
        chat_id, chat_type)

    if chat_type == "userToUser":
        for i, msg in enumerate(msgs_in_chat):
            msgs_in_chat[i] = {
                "content":
                msg.content,
                "datetime":
                f"{msg.datetime}+00:00",
                "fromId":
                msg.from_id,
                "fromName":
                User.get_by_id(msg.from_id).name
                if msg.from_id is not current_user.id else current_user.name,
                "toId":
                msg.to_id
            }

    elif chat_type == "chatGroup" or chat_type == "projectChatGroup":
        for i, msg in enumerate(msgs_in_chat):
            msgs_in_chat[i] = {
                "content":
                msg.content,
                "datetime":
                f"{msg.datetime}+00:00",
                "fromId":
                msg.from_id,
                "fromName":
                User.get_by_id(msg.from_id).name
                if msg.from_id is not current_user.id else current_user.name
            }

    else:
        abort(400)

    return jsonify(msgs_in_chat), 200
Beispiel #3
0
async def update_user(user_id: UUID, data: UserUpdateRequest) -> Response:
    user = await get_or_404(User.select(), id=user_id)

    update_data = data.dict(exclude_unset=True)

    course = set_attrs(user, **update_data)
    await db_manager.update(course)
    return APIResponse(UserResponse.from_orm(course).dict())
Beispiel #4
0
def user_profile_projects(username):
    user = User.get_by_name(username)
    if not user:
        abort(404)
    if not user.sign_up_complete:
        abort(404)

    current_user_is_friend_with_user = current_user.is_friend_with(user.id)

    projects = []
    for project in user.projects.order_by(Project.name):

        if current_user.id == user.id \
                or project.visibility == "public" \
                or (project.visibility == "friends" and current_user_is_friend_with_user) \
                or (project.visibility == "private" and current_user.is_project_collaborator_of(project.id)):

            projects.append({
                "name": project.name,
                "link": f"/{project.owner_name}/{project.name}",
                "desc": project.project_desc
            })

    if current_user.id == user.id:
        return render_template(
            "user_profile_projects.html.j2",
            user_id=user.id,
            user_profile_pic_url=user.avatar_url,
            username=username,
            useremail=user.email,
            userprofile_desc=user.profile_desc,
            token=user.set_token(),
            projects=projects,
            current_user_is_friend_with_user=current_user_is_friend_with_user)

    elif not user.private or current_user_is_friend_with_user:
        if user.email_private:
            return render_template("user_profile_projects.html.j2",
                                   user_id=user.id,
                                   user_profile_pic_url=user.avatar_url,
                                   username=username,
                                   userprofile_desc=user.profile_desc,
                                   projects=projects,
                                   current_user_is_friend_with_user=
                                   current_user_is_friend_with_user)

        return render_template(
            "user_profile_projects.html.j2",
            user_id=user.id,
            user_profile_pic_url=user.avatar_url,
            username=username,
            useremail=user.email,
            userprofile_desc=user.profile_desc,
            projects=projects,
            current_user_is_friend_with_user=current_user_is_friend_with_user)

    abort(404)
Beispiel #5
0
def login():

    post_to = request.path

    forgot_password_link = "/forgot-password"

    url_query_str = ""

    continue_to = request.args.get("continue")
    if continue_to:
        url_query_str = "?continue=" + urllib.parse.quote(continue_to, safe="")
        post_to += url_query_str
        forgot_password_link += url_query_str

    # -- POST
    if request.method == "POST":
        form = request.form

        user = User.get_by_name_or_email(form["username"])
        if user:
            if bcrypt.check_password_hash(user.password_hash,
                                          form["password"]):
                if form.get("keepUserLoggedIn") or user.stay_logged_in:
                    login_user(user, True, timedelta(days=365))
                    if not user.stay_logged_in:
                        user.stay_logged_in = True
                        db.session.commit()
                else:
                    login_user(user)

                continue_to = request.args.get("continue")

                if user.email_pending_verification is not None:
                    return redirect(
                        f"/verify-email/{user.email_verification_case_id}{url_query_str}"
                    )

                if continue_to:
                    return redirect(continue_to)
                return redirect("/")

        return render_template(
            "login.html.j2",
            post_to=post_to,
            forgot_password_link=f"/forgot-password{url_query_str}",
            username=form["username"],
            invalidLogin=True)

    # -- GET
    if current_user.is_authenticated():
        return redirect("/")

    return render_template(
        "login.html.j2",
        post_to=post_to,
        forgot_password_link=f"/forgot-password{url_query_str}")
Beispiel #6
0
async def get_current_username(
        credentials: HTTPBasicCredentials = Depends(security)):
    user = await get_or_404(User.select(), email=credentials.username)

    if credentials.password != user.password:
        raise HTTPException(
            status_code=HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Basic"},
        )
    return user.id
Beispiel #7
0
def user_profile_friends(username):
    user = User.get_by_name(username)
    if not user:
        abort(404)
    if not user.sign_up_complete:
        abort(404)

    current_user_is_friend_with_user = current_user.is_friend_with(user.id)

    friends = []
    for friend in db.session.query(User)\
            .filter(User.id.in_(db.session.query(Friendship.friend_id).filter_by(user_id=user.id)))\
            .with_entities(User.name, User.small_avatar_url):
        friends.append({
            "name": friend.name,
            "link": f"/{friend.name}",
            "picUrl": friend.small_avatar_url
        })

    if current_user.id == user.id:
        return render_template(
            "user_profile_friends.html.j2",
            user_id=user.id,
            user_profile_pic_url=user.avatar_url,
            username=username,
            useremail=user.email,
            userprofile_desc=user.profile_desc,
            token=user.set_token(),
            friends=friends,
            current_user_is_friend_with_user=current_user_is_friend_with_user)

    elif not user.private or current_user_is_friend_with_user:
        if user.email_private:
            return render_template("user_profile_friends.html.j2",
                                   user_id=user.id,
                                   user_profile_pic_url=user.avatar_url,
                                   username=username,
                                   userprofile_desc=user.profile_desc,
                                   friends=friends,
                                   current_user_is_friend_with_user=
                                   current_user_is_friend_with_user)

        return render_template(
            "user_profile_friends.html.j2",
            user_id=user.id,
            user_profile_pic_url=user.avatar_url,
            username=username,
            useremail=user.email,
            userprofile_desc=user.profile_desc,
            friends=friends,
            current_user_is_friend_with_user=current_user_is_friend_with_user)

    abort(404)
Beispiel #8
0
def new_friend_page():
    if not current_user.is_authenticated():
        return redirect("/")

    continue_to = request.args.get("continue")
    if not continue_to:
        continue_to = "/"

    name = request.args.get("name")
    if not name:
        name = ""

    if request.method == "POST":
        form = request.form
        target = User.get_by_name_or_email(form["name"])

        if not target:
            return render_template("new_friend.html.j2",
                                   name_does_not_exist=True,
                                   continue_to=continue_to,
                                   post_to=f"/new-friend?continue={urllib.parse.quote(continue_to, safe='')}")

        if target.id == current_user.id \
                or Friendship.query.filter_by(user_id=current_user.id, friend_id=target.id).scalar() \
                or FriendshipRequest.query.filter_by(from_id=current_user.id, to_id=target.id).scalar():
            return render_template("new_friend.html.j2",
                                   invalid_target=True,
                                   continue_to=continue_to,
                                   post_to=f"/new-friend?continue={urllib.parse.quote(continue_to, safe='')}")

        if not target.block_all_friendship_requests:
            friendship_request = FriendshipRequest(current_user.id, target.id)
            db.session.add(friendship_request)
            db.session.commit()

            socketio.emit("receive_friendship_request",
                          {"id": friendship_request.id,
                           "type": "friendshipRequest",
                           "fromName": current_user.name,
                           "picUrl": current_user.small_avatar_url,
                           "goToUrl": f"/{current_user.name}",
                           "datetime": f"{friendship_request.datetime}+00:00"},
                          room=target.id,
                          namespace="/")

        return redirect(continue_to)

    return render_template("new_friend.html.j2",
                           continue_to=continue_to,
                           name=name)
    def on_change_project_owner(data):
        if data["projectId"] in rooms() and current_user.is_project_owner_of(
                data["projectId"]):
            project = Project.query.filter_by(id=data["projectId"]).first()

            new_owner_user = User.get_by_name_or_email(data["nameOrEmail"])

            if not new_owner_user or not new_owner_user.is_project_collaborator_of(data["projectId"]) \
                    or Project.query.filter_by(owner_name=new_owner_user.name).scalar():
                emit("change_project_owner_error_invalid_target",
                     room=request.sid)
                return

            ProjectCollaboratorLink.query.filter_by(
                project_id=data["projectId"],
                user_id=new_owner_user.id).delete()
            project.owner_name = new_owner_user.name
            db.session.add(
                ProjectCollaboratorLink(data["projectId"], current_user.id,
                                        "admin"))
            db.session.commit()

            project_data = {
                "projectId": project.id,
                "name": project.name,
                "ownerName": project.owner_name,
                "projectDesc": project.project_desc
            }

            for collab in db.session.query(
                    ProjectCollaboratorLink.user_id).filter_by(
                        project_id=project.id).all():
                emit("update_project_attributes",
                     project_data,
                     room=collab.user_id,
                     namespace="/")

            emit("update_project_attributes",
                 project_data,
                 room=new_owner_user.id,
                 namespace="/")

            emit("force_reload", room=current_user.id, namespace="/")
            emit("force_reload", room=new_owner_user.id, namespace="/")
Beispiel #10
0
    def on_add_friend_to_chat_group(data):
        current_user_member_link = ChatGroupMemberLink.query.filter_by(user_id=current_user.id,
                                                                       chat_group_id=data["chatGroupId"]) \
            .first()
        if not current_user_member_link or current_user_member_link.user_role != "admin":
            return

        friend = User.get_by_name_or_email(data["friendNameOrEmail"])

        if not friend \
                or ChatGroupMemberLink.query.filter_by(user_id=friend.id, chat_group_id=data["chatGroupId"]).scalar()\
                or not current_user.is_friend_with(friend.id):
            emit("add_friend_to_chat_group_error_invalid_target", room=current_user.id)
            return

        chat_group = ChatGroup.query.filter_by(id=data["chatGroupId"]).first()

        db.session.add(ChatGroupMemberLink(data["chatGroupId"], friend.id, "default"))
        db.session.commit()

        member_ids_to_emit_new_chat_group_member_info_to = []

        members = {}

        for member_user in db.session.query(ChatGroupMemberLink) \
                .filter_by(chat_group_id=chat_group.id) \
                .join(User, User.id == ChatGroupMemberLink.user_id)\
                .with_entities(User.id,
                               User.name,
                               User.small_avatar_url,
                               ChatGroupMemberLink.user_role):

            members[member_user.id] = {
                "id": member_user.id,
                "name": member_user.name,
                "picUrl": member_user.small_avatar_url,
                "goToUrl": f"/{member_user.name}",
                "role": member_user.user_role
            }

            if member_user.id != friend.id:
                member_ids_to_emit_new_chat_group_member_info_to.append(member_user.id)

        last_msg = friend.get_last_msg(chat_group.id, "chatGroup")

        emit("new_chat_group",
             {"id": chat_group.id,
              "type": "chatGroup",
              "name": chat_group.name,
              "unreadCount": friend.get_unread_count_in_chat(chat_group.id, "chatGroup"),
              "lastMsg": {"content": last_msg.content, "datetime": f"{last_msg.datetime}+00:00"} if last_msg
              else "None",
              "picUrl": "/static/img/group.png",
              "roleOfCurrentUser": "******",
              "members": members},
             room=friend.id)

        for id_ in member_ids_to_emit_new_chat_group_member_info_to:
            emit("new_chat_group_member",
                 {"chatGroupId": chat_group.id,
                  "chatGroupType": "chatGroup",
                  "member": {"id": friend.id,
                             "name": friend.name,
                             "picUrl": friend.small_avatar_url,
                             "goToUrl": f"/{friend.name}",
                             "role": "default"}
                  },
                 room=id_)

        emit("successfully_added_friend_to_chat_group", room=current_user.id)
    def on_add_friend_to_project(data):
        if data["projectId"] in rooms() and current_user.is_project_owner_of(
                data["projectId"]):
            project = Project.query.filter_by(id=data["projectId"]).first()

            friend = User.get_by_name_or_email(data["friendNameOrEmail"])

            if not friend or not current_user.is_friend_with(friend.id) \
                    or friend.is_project_collaborator_of(project.id):
                emit("add_friend_to_project_error_invalid_target",
                     room=request.sid)
                return

            if data["role"] != "admin" and data["role"] != "access-only":
                return

            db.session.add(
                ProjectCollaboratorLink(data["projectId"], friend.id,
                                        data["role"]))

            project_chat_group = project.chat_group.first()
            if project_chat_group:

                member_data = {
                    friend.id: {
                        "id": friend.id,
                        "role": "default",
                        "name": friend.name,
                        "picUrl": friend.small_avatar_url,
                        "goToUrl": f"/{friend.name}"
                    }
                }

                for member_user in db.session.query(ProjectChatGroupMemberLink) \
                        .filter_by(project_chat_group_id=project_chat_group.id) \
                        .join(User, User.id == ProjectChatGroupMemberLink.user_id) \
                        .with_entities(User.id,
                                       User.name,
                                       User.small_avatar_url):

                    member_data[member_user.id] = {
                        "id": member_user.id,
                        "name": member_user.name,
                        "picUrl": member_user.small_avatar_url,
                        "goToUrl": f"/{member_user.name}",
                        "role": "default"
                    }

                    emit("new_chat_group_member", {
                        "chatGroupId": project_chat_group.id,
                        "chatGroupType": "projectChatGroup",
                        "member": {
                            "id": friend.id,
                            "name": friend.name,
                            "picUrl": friend.small_avatar_url,
                            "goToUrl": f"/{friend.name}",
                            "role": "default"
                        }
                    },
                         namespace="/",
                         room=member_user.id)

                db.session.add(
                    ProjectChatGroupMemberLink(project_chat_group.id,
                                               friend.id, "default"))

                last_msg = current_user.get_last_msg(project_chat_group.id,
                                                     "projectChatGroup")
                last_msg = {
                    "content": last_msg.content,
                    "datetime": f"{last_msg.datetime}+00:00"
                } if last_msg else "None"

                emit("new_chat_group", {
                    "id": project_chat_group.id,
                    "type": "projectChatGroup",
                    "name": project_chat_group.name,
                    "unreadCount": 0,
                    "lastMsg": last_msg,
                    "picUrl": "/static/img/group.png",
                    "roleOfCurrentUser": "******",
                    "members": member_data
                },
                     room=friend.id,
                     namespace="/")

            db.session.commit()

            emit("successfully_added_friend_to_project", room=request.sid)

            emit("new_project_collab", {
                "id": friend.id,
                "name": friend.name,
                "picUrl": friend.small_avatar_url,
                "goToUrl": f"/{friend.name}",
                "role": data["role"]
            },
                 room=data["projectId"])

            emit("now_collab_of_project", {
                "id": data["projectId"],
                "name": project.name,
                "ownerName": project.owner_name,
                "goToUrl": f"/{project.owner_name}/{project.name}"
            },
                 namespace="/",
                 room=friend.id)
Beispiel #12
0
def user_profile_settings(username):
    if not current_user.name == username:
        abort(404)
    user = User.get_by_name(username)
    if not user:
        abort(404)
    if not user.sign_up_complete:
        abort(404)

    invalid_names_list = invalid_names()

    # -- POST
    if request.method == "POST":

        # - "switch" settings

        request_json = request.get_json()

        if request_json and request_json["setting"]:

            if request_json["token"] == user.token:

                # Email private

                if request_json["setting"] == "useremailPrivate":
                    if request_json["value"]:
                        user.email_private = True
                    else:
                        user.email_private = False

                # Profile private

                elif request_json["setting"] == "userprofilePrivate":
                    if request_json["value"]:
                        user.private = True
                    else:
                        user.private = False

                # Stay logged in

                elif request_json["setting"] == "keepUserLoggedIn":
                    if request_json["value"] and not user.stay_logged_in:
                        user.stay_logged_in = True
                        logout_user()
                        login_user(user, True, timedelta(days=365))
                    elif not request_json["value"] and user.stay_logged_in:
                        if user.stay_logged_in:
                            user.stay_logged_in = False
                            logout_user()
                            login_user(user)
                        user.stay_logged_in = False

                # Block all friendship requests

                elif request_json["setting"] == "blockAllFriendshipRequests":
                    if request_json["value"]:
                        user.block_all_friendship_requests = True
                    else:
                        user.block_all_friendship_requests = False

                db.session.commit()
                return make_response(Response(""), 200)

            else:
                abort(419)

        # - "form" settings

        form = request.form

        if form and form["submit"] != "editProfile":

            lex, _ = get_lexicon_and_lang("user_profile_settings_view_func")

            if form["token"] == user.token:

                # Change username

                if form["submit"] == "changeUsername":
                    change_username_invalid = False
                    change_username_username_error_text = ""
                    change_username_password_error_text = ""

                    if User.query.filter(User.name.ilike(form['newUsername'])).scalar() \
                            or form['newUsername'] in invalid_names_list:
                        change_username_username_error_text = lex[
                            "This username is not available"]
                        change_username_invalid = True

                    regexexp = re.compile("^[a-zA-Z][a-zA-Z0-9_-]*$")
                    if not 1 <= len(
                            form["newUsername"]) <= 16 or not regexexp.search(
                                form["newUsername"]):
                        change_username_username_error_text = lex[
                            "Invalid username"]
                        change_username_invalid = True

                    if not bcrypt.check_password_hash(user.password_hash,
                                                      form["password"]):
                        change_username_password_error_text = lex[
                            "Wrong password"]
                        change_username_invalid = True

                    if change_username_invalid:
                        return render_template("user_profile_settings.html.j2",
                                               user_id=user.id,
                                               invalid_names=invalid_names_list,
                                               user_profile_pic_url=user.avatar_url,
                                               username=username,
                                               userprofile_desc=user.profile_desc,
                                               useremail=user.email,
                                               token=user.set_token(),
                                               change_username_invalid=True,
                                               new_username=form['newUsername'],
                                               change_username_password_error_text=change_username_password_error_text,
                                               change_username_username_error_text=change_username_username_error_text
                                               ), \
                               400

                    for project in user.projects:
                        project.owner_name = form["newUsername"]

                        project_data = {
                            "projectId": project.id,
                            "name": project.name,
                            "ownerName": project.owner_name,
                            "projectDesc": project.project_desc
                        }

                        for collab in db.session.query(ProjectCollaboratorLink.user_id)\
                                .filter_by(project_id=project.id):

                            socketio.emit("update_project_attributes",
                                          project_data,
                                          room=collab.user_id,
                                          namespace="/")

                        socketio.emit("update_project_attributes",
                                      project_data,
                                      room=user.id,
                                      namespace="/")

                    user.name = form["newUsername"]

                    # change avatar if default
                    bucket, _ = split_s3_obj_url(user.avatar_url)
                    if bucket != app.config[
                            "S3_BUCKET_NAME"]:  # => default avatar
                        rand_n = random.randint(1, 4)
                        user.avatar_url = f"{app.config['S3_STATIC_BUCKET_URL']}/default_avatar/" \
                                          f"{form['newUsername'][0].lower()}{rand_n}x.png"
                        user.small_avatar_url = f"{app.config['S3_STATIC_BUCKET_URL']}/default_avatar/" \
                                                f"{form['newUsername'][0].lower()}{rand_n}s.png"

                    db.session.commit()

                    for friendship in user.friendships:
                        socketio.emit("update_friend_name", {
                            "id": user.id,
                            "name": user.name
                        },
                                      room=friendship.friend_id,
                                      namspace="/")

                    return redirect(f"/{user.name}/settings")

                # Change email

                if form["submit"] == "changeEmail":
                    change_email_invalid = False
                    change_email_email_error_text = ""
                    change_email_password_error_text = ""

                    if User.get_by_name_or_email(form['newEmail']) \
                            or User.query.filter_by(email_pending_verification=form['newEmail']).scalar():
                        change_email_email_error_text = lex[
                            "This email address is not available"]
                        change_email_invalid = True

                    if not 1 <= len(form["newEmail"]) <= 32:
                        change_email_email_error_text = lex[
                            "Invalid email address"]
                        change_email_invalid = True

                    if not bcrypt.check_password_hash(user.password_hash,
                                                      form["password"]):
                        change_email_password_error_text = lex[
                            "Wrong password"]
                        change_email_invalid = True

                    if change_email_invalid:
                        return render_template("user_profile_settings.html.j2",
                                               user_id=user.id,
                                               invalid_names=invalid_names_list,
                                               user_profile_pic_url=user.avatar_url,
                                               username=username,
                                               userprofile_desc=user.profile_desc,
                                               useremail=user.email,
                                               token=user.set_token(),
                                               change_email_invalid=True,
                                               new_email=form['newEmail'],
                                               change_email_email_error_text=change_email_email_error_text,
                                               change_email_password_error_text=change_email_password_error_text
                                               ), \
                               400

                    email_verification_case_id = uuid4().hex
                    email_verification_code = token_urlsafe(16)

                    user.email_pending_verification = form["newEmail"]
                    user.email_verification_case_id = email_verification_case_id
                    user.email_verification_code = email_verification_code
                    db.session.commit()

                    email_verification_path_with_code = email_verification_case_id + f"?code={email_verification_code}"

                    email_html = render_template(
                        "email/verify_new_email.html.j2",
                        user_id=user.id,
                        username=user.name,
                        email=user.email_pending_verification,
                        code=email_verification_code,
                        link="https://taskstack.org/verify-email/" +
                        email_verification_path_with_code)

                    email_txt = render_template(
                        "email/verify_new_email.txt.j2",
                        user_id=user.id,
                        username=user.name,
                        email=user.email_pending_verification,
                        code=email_verification_code,
                        link="https://taskstack.org/verify-email/" +
                        email_verification_path_with_code)

                    ses_cli.send_email(
                        Source='*****@*****.**',
                        Destination={
                            'ToAddresses': [
                                user.email_pending_verification,
                            ]
                        },
                        Message={
                            'Subject': {
                                'Data':
                                lex['[Taskstack] Verify your new email address'],
                                'Charset':
                                'UTF-8'
                            },
                            'Body': {
                                'Text': {
                                    'Data': email_txt,
                                    'Charset': 'UTF-8'
                                },
                                'Html': {
                                    'Data': email_html,
                                    'Charset': 'UTF-8'
                                }
                            }
                        })

                    return redirect(
                        f"/verify-email/{email_verification_case_id}"
                        f"?continue={urllib.parse.quote(request.path, safe='')}"
                    )

                # Change password

                elif form["submit"] == "changePassword":
                    change_password_invalid = False
                    change_password_password_error_text = ""
                    change_password_new_password_error_text = ""

                    if not bcrypt.check_password_hash(user.password_hash,
                                                      form["old_password"]):
                        change_password_password_error_text = lex[
                            "Wrong password"]
                        change_password_invalid = True

                    if not 8 <= len(form["newPassword"]) <= 64:
                        change_password_password_error_text = lex[
                            "Invalid password"]
                        change_password_invalid = False

                    if change_password_invalid:
                        return render_template("user_profile_settings.html.j2",
                                               user_id=user.id,
                                               invalid_names=invalid_names_list,
                                               user_profile_pic_url=user.avatar_url,
                                               username=username,
                                               useremail=user.email,
                                               userprofile_desc=user.profile_desc,
                                               token=user.set_token(),
                                               change_password_invalid=True,
                                               change_password_password_error_text=change_password_password_error_text,
                                               change_password_new_password_error_text=
                                               change_password_new_password_error_text
                                               ), \
                               400

                    user.password_hash = bcrypt.generate_password_hash(
                        form["newPassword"]).decode("utf-8")
                    db.session.commit()

                    return redirect(f"/{user.name}/settings")

                # Delete account

                elif form["submit"] == "deleteAccount":
                    if not bcrypt.check_password_hash(user.password_hash,
                                                      form["password"]):
                        delete_account_password_error_text = lex[
                            "Wrong password"]

                        return render_template("user_profile_settings.html.j2",
                                               user_id=user.id,
                                               invalid_names=invalid_names_list,
                                               user_profile_pic_url=user.avatar_url,
                                               username=username,
                                               useremail=user.email,
                                               userprofile_desc=user.userprofile_desc,
                                               token=user.set_token(),
                                               delete_account_invalid=True,
                                               delete_account_password_error_text=delete_account_password_error_text
                                               ), \
                            400

                    logout_user()

                    for project in user.projects.with_entities(Project.id):
                        socketio.emit("project_deleted",
                                      room=project.id,
                                      namespace="/project")

                    # delete user avatar from s3 bucket
                    avatar_bucket, avatar_key = split_s3_obj_url(
                        user.avatar_url)
                    small_avatar_bucket, small_avatar_key = split_s3_obj_url(
                        user.small_avatar_url)
                    if avatar_bucket == app.config["S3_BUCKET_NAME"]:
                        s3_cli.delete_object(Bucket=avatar_bucket,
                                             Key=avatar_key)
                        s3_cli.delete_object(Bucket=small_avatar_bucket,
                                             Key=small_avatar_key)

                    # delete projects
                    for project in user.projects:
                        for _list in project.lists:
                            for card in _list.cards:
                                for file in card.attached_files:
                                    _, key = split_s3_obj_url(file.url)
                                    s3_cli.delete_object(
                                        Bucket=app.config["S3_BUCKET_NAME"],
                                        Key=key)
                                    db.session.delete(file)

                                CardUserAssignment.query.filter_by(
                                    card_id=card.id).delete()

                                db.session.delete(card)

                            for file in _list.attached_files:
                                _, key = split_s3_obj_url(file.url)
                                s3_cli.delete_object(
                                    Bucket=app.config["S3_BUCKET_NAME"],
                                    Key=key)
                                db.session.delete(file)

                            db.session.delete(_list)

                        project_chat_group = project.chat_group.first()
                        if project_chat_group:
                            ProjectChatGroupMsgStatus.query.filter_by(
                                project_chat_group_id=project_chat_group.id
                            ).delete()
                            ProjectChatGroupMsg.query.filter_by(
                                project_chat_group_id=project_chat_group.id
                            ).delete()
                            project_chat_group.member_links.delete()
                            db.session.delete(project_chat_group)

                        for collab in db.session.query(ProjectCollaboratorLink.user_id)\
                                .filter_by(project_id=project.id):

                            socketio.emit("removed_as_collab_of_project",
                                          project.id,
                                          room=collab.user_id,
                                          namspace="/")

                            if project_chat_group:
                                socketio.emit("chat_group_removed", {
                                    "type": "projectChatGroup",
                                    "id": project_chat_group.id
                                },
                                              room=collab.user_id,
                                              namspace="/")

                        ProjectCollaboratorLink.query.filter_by(
                            project_id=project.id).delete()

                        db.session.delete(project)

                    # delete project collab links
                    for project_collaboration_link in user.project_collaboration_links:

                        socketio.emit(
                            "project_collab_removed", {"id": user.id},
                            room=project_collaboration_link.project_id,
                            namespace="/project")

                        db.session.delete(project_collaboration_link)

                    # delete card assignments
                    user.card_assignments.delete()

                    # delete chat group member links
                    for chat_group_member_link in user.chat_group_member_links:
                        for member in db.session.query(ChatGroupMemberLink.user_id) \
                                .filter_by(chat_group_id=chat_group_member_link.chat_group_id).all():
                            socketio.emit(
                                "chat_group_member_removed", {
                                    "userId": user.id,
                                    "chatGroupId":
                                    chat_group_member_link.chat_group_id,
                                    "chatGroupType": "chatGroup"
                                },
                                room=member.user_id,
                                namspace="/")

                        db.session.delete(chat_group_member_link)

                    for project_chat_group_member_link in user.project_chat_group_member_links:
                        for member in db.session.query(ProjectChatGroupMemberLink.user_id) \
                                .filter_by(project_chat_group_id=project_chat_group_member_link.chat_group_id).all():
                            socketio.emit("chat_group_member_removed", {
                                "userId":
                                user.id,
                                "chatGroupId":
                                project_chat_group_member_link.chat_group_id,
                                "chatGroupType":
                                "projectChatGroup"
                            },
                                          room=member.user_id,
                                          namspace="/")

                        db.session.delete(project_chat_group_member_link)

                    # delete friendships + friendship reqs
                    for friendship in user.friendships:
                        socketio.emit("friend_removed", {"id": user.id},
                                      room=friendship.friend_id,
                                      namspace="/")

                    Friendship.query.filter(
                        or_(Friendship.friend_id == user.id,
                            Friendship.user_id == user.id)).delete()
                    FriendshipRequest.query.filter(
                        or_(FriendshipRequest.from_id == user.id, FriendshipRequest.to_id == user.id)) \
                        .delete()

                    # delete msgs
                    Msg.query.filter(
                        or_(Msg.from_id == user.id,
                            Msg.to_id == user.id)).delete()
                    ChatGroupMsg.query.filter_by(from_id=user.id).delete()
                    ProjectChatGroupMsg.query.filter_by(
                        from_id=user.id).delete()
                    ChatGroupMsgStatus.query.filter_by(
                        user_id=user.id).delete()
                    ProjectChatGroupMsgStatus.query.filter_by(
                        user_id=user.id).delete()

                    # delete pot. resulting empty chat groups
                    ChatGroup.query.filter(ChatGroup.id.notin_(db.session.query(ChatGroupMemberLink.chat_group_id))) \
                        .delete(synchronize_session=False)
                    ProjectChatGroup.query \
                        .filter(ChatGroup.id
                                .notin_(db.session.query(ProjectChatGroupMemberLink.project_chat_group_id)))\
                        .delete(synchronize_session=False)

                    db.session.delete(user)

                    db.session.commit()

                    return redirect("/")

            else:
                return render_template("user_profile_settings.html.j2",
                                       user_id=user.id,
                                       invalid_names=invalid_names_list,
                                       user_profile_pic_url=user.avatar_url,
                                       username=username,
                                       useremail=user.email,
                                       userprofile_desc=user.profile_desc, token=user.set_token(),
                                       invalid_token=True
                                       ), \
                       419

        abort(400)

    # -- GET
    return render_template("user_profile_settings.html.j2",
                           user_id=user.id,
                           invalid_names=invalid_names_list,
                           user_profile_pic_url=user.avatar_url,
                           username=username,
                           useremail=user.email,
                           userprofile_desc=user.profile_desc,
                           token=user.set_token())
Beispiel #13
0
async def get_users() -> Response:
    users = await execute(User.select())
    return APIResponse(invoke(map(UserResponse.from_orm, users), 'dict'))
Beispiel #14
0
async def get_user(user_id: UUID = Depends(get_current_username)) -> Response:
    user = await get_or_404(User.select(), id=user_id)
    return APIResponse(UserResponse.from_orm(user).dict(),
                       status_code=HTTPStatus.OK)
Beispiel #15
0
def user_profile(username):
    user = User.get_by_name(username)
    if not user:
        abort(404)
    if not user.sign_up_complete:
        abort(404)

    # -- POST
    if request.method == "POST":
        form = request.form

        if form["submit"] == "editProfile":
            if current_user.name != username:
                abort(404)

            if form["token"] != user.token:
                return make_response(Response(""), 419)

            try:
                # change profile pic
                pic = PIL.Image.open(request.files["newProfilePic"].stream)
                small_pic = pic.copy()
                pic.thumbnail((280, 280))
                small_pic.thumbnail((50, 50))

                pic_fileobj = io.BytesIO()
                pic.save(pic_fileobj, format="png")
                pic_fileobj.seek(0)

                small_pic_fileobj = io.BytesIO()
                small_pic.save(small_pic_fileobj, format="png")
                small_pic_fileobj.seek(0)

                key = uuid4().hex + ".png"
                small_pic_key = uuid4().hex + ".png"

                s3_cli.upload_fileobj(pic_fileobj,
                                      app.config["S3_BUCKET_NAME"],
                                      key,
                                      ExtraArgs={
                                          'ACL': 'public-read',
                                          'CacheControl': 'max-age: 86400',
                                          "ContentType": "image/png"
                                      })

                s3_cli.upload_fileobj(small_pic_fileobj,
                                      app.config["S3_BUCKET_NAME"],
                                      small_pic_key,
                                      ExtraArgs={
                                          'ACL': 'public-read',
                                          'CacheControl': 'max-age: 86400',
                                          "ContentType": "image/png"
                                      })

                #   delete prev avatar if not default avatar
                prev_bucket, prev_key = split_s3_obj_url(user.avatar_url)
                small_pic_prev_bucket, small_pic_prev_key = split_s3_obj_url(
                    user.small_avatar_url)
                if prev_bucket == app.config[
                        "S3_BUCKET_NAME"]:  # => not default avatar
                    s3_cli.delete_object(Bucket=prev_bucket, Key=prev_key)
                    s3_cli.delete_object(Bucket=small_pic_prev_bucket,
                                         Key=small_pic_prev_key)

                user.avatar_url = app.config["S3_BUCKET_URL"] + "/" + key
                user.small_avatar_url = app.config[
                    "S3_BUCKET_URL"] + "/" + small_pic_key

            except BadRequestKeyError:
                pass

            # change profile desc
            if len(form["newProfileDesc"]) <= 256:
                user.profile_desc = form["newProfileDesc"]

            db.session.commit()

            return make_response(Response(""), 200)

        elif form["submit"] == "removeFriend":
            f1 = Friendship.query.filter_by(user_id=current_user.id,
                                            friend_id=user.id).first()
            f2 = Friendship.query.filter_by(user_id=user.id,
                                            friend_id=current_user.id).first()

            if f1 and f2:
                db.session.delete(f1)
                db.session.delete(f2)
                db.session.commit()

            socketio.emit("friend_removed", {"id": current_user.id},
                          room=user.id,
                          namespace="/")

            return make_response(Response(""), 200)

        abort(400)

    # -- GET
    if current_user.name == username or not user.private or current_user.is_friend_with(
            user.id):
        return redirect(f"/{username}/projects")

    abort(404)
Beispiel #16
0
async def create_user(data: UserCreateRequest) -> Response:
    user_id = await execute(User.insert(**data.dict()))
    user = first(await execute(User.filter(id=user_id)))
    return APIResponse(UserResponse.from_orm(user).dict(),
                       status_code=HTTPStatus.CREATED)
Beispiel #17
0
def home():
    # home if auth
    if current_user.is_authenticated():

        # projects

        projects_where_is_owner = []
        for project in current_user.projects:
            projects_where_is_owner.append({
                "id":
                project.id,
                "ownerName":
                project.owner_name,
                "name":
                project.name,
                "goToUrl":
                f"/{project.owner_name}/{project.name}"
            })

        projects_where_is_collab = current_user.get_projects_where_is_collaborator(
        )
        for i, project in enumerate(projects_where_is_collab):
            projects_where_is_collab[i] = {
                "id": project.id,
                "ownerName": project.owner_name,
                "name": project.name,
                "goToUrl": f"/{project.owner_name}/{project.name}"
            }

        # notifications

        notifications = current_user.get_notifications()
        for i, notification in enumerate(notifications):
            from_user = User.get_by_id(notification.from_id)

            if isinstance(notification, Msg):
                notifications[i] = {
                    "id": notification.id,
                    "type": "msg",
                    "chatType": "userToUser",
                    "picUrl": from_user.small_avatar_url,
                    "goToUrl": f"/{from_user.name}",
                    "goToChatUrl": f"/chat?with={from_user.name}",
                    "datetime": f"{notification.datetime}+00:00",
                    "content": notification.content
                }

            elif isinstance(notification, ChatGroupMsg):
                notifications[i] = {
                    "id": notification.id,
                    "type": "msg",
                    "chatType": "chatGroup",
                    "picUrl": from_user.small_avatar_url,
                    "goToUrl": f"/{from_user.name}",
                    "goToChatUrl": "/chat",
                    "datetime": f"{notification.datetime}+00:00",
                    "content": notification.content
                }

            elif isinstance(notification, ProjectChatGroupMsg):
                notifications[i] = {
                    "id": notification.id,
                    "type": "msg",
                    "chatType": "projectChatGroup",
                    "picUrl": from_user.small_avatar_url,
                    "goToUrl": f"/{from_user.name}",
                    "goToChatUrl": "/chat",
                    "datetime": f"{notification.datetime}+00:00",
                    "content": notification.content
                }

            elif isinstance(notification, FriendshipRequest):
                notifications[i] = {
                    "id": notification.id,
                    "type": "friendshipRequest",
                    "picUrl": from_user.small_avatar_url,
                    "goToUrl": f"/{from_user.name}",
                    "datetime": f"{notification.datetime}+00:00"
                }

        # friends

        friends = current_user.get_friends()
        for i, friend in enumerate(friends):
            friends[i] = {
                "id": friend.id,
                "name": friend.name,
                "picUrl": friend.small_avatar_url,
                "goToUrl": f"/{friend.name}"
            }

        return render_template("home.auth.html.j2",
                               projects={
                                   "whereOwner": projects_where_is_owner,
                                   "whereCollab": projects_where_is_collab
                               },
                               notifications=notifications,
                               friends=friends)

    # home if not auth
    return render_template("home.unauth.html.j2")
Beispiel #18
0
async def delete_user(user_id: UUID) -> Response:
    await get_or_404(User.select(), id=user_id)
    await execute(User.delete().where(User.id == user_id))
    return APIResponse(status_code=HTTPStatus.NO_CONTENT)
Beispiel #19
0
def load_user(user_id):
    return User.get_by_id(user_id)
Beispiel #20
0
def chat():
    if not current_user.is_authenticated():
        abort(404)

    chats = {"userToUser": {}, "chatGroup": {}, "projectChatGroup": {}}

    for friend in current_user.get_friends():
        last_msg = current_user.get_last_msg(friend.id, "userToUser")
        last_msg = {
            "content": last_msg.content,
            "datetime": f"{last_msg.datetime}+00:00"
        } if last_msg else "None"

        chats["userToUser"][friend.id] = {
            "id":
            friend.id,
            "type":
            "userToUser",
            "name":
            friend.name,
            "unreadCount":
            current_user.get_unread_count_in_chat(friend.id, "userToUser"),
            "lastMsg":
            last_msg,
            "picUrl":
            friend.small_avatar_url,
            "goToUrl":
            f"/{friend.name}"
        }

    for chat_group in current_user.get_chat_groups_where_member():
        last_msg = current_user.get_last_msg(chat_group.id, "chatGroup")
        last_msg = {
            "content": last_msg.content,
            "datetime": f"{last_msg.datetime}+00:00"
        } if last_msg else "None"

        members = {}

        for member_user in db.session.query(ChatGroupMemberLink) \
                .filter_by(chat_group_id=chat_group.id) \
                .join(User, User.id == ChatGroupMemberLink.user_id) \
                .with_entities(User.id,
                               User.name,
                               User.small_avatar_url,
                               ChatGroupMemberLink.user_role):

            members[member_user.id] = {
                "id": member_user.id,
                "name": member_user.name,
                "picUrl": member_user.small_avatar_url,
                "goToUrl": f"/{member_user.name}",
                "role": member_user.user_role
            }

        chats["chatGroup"][chat_group.id] = {
            "id":
            chat_group.id,
            "type":
            "chatGroup",
            "name":
            chat_group.name,
            "unreadCount":
            current_user.get_unread_count_in_chat(chat_group.id, "chatGroup"),
            "lastMsg":
            last_msg,
            "picUrl":
            "/static/img/group.png",
            "roleOfCurrentUser":
            chat_group.user_role,
            "members":
            members
        }

    for project_chat_group in current_user.get_project_chat_groups_where_member(
    ):
        last_msg = current_user.get_last_msg(project_chat_group.id,
                                             "projectChatGroup")
        last_msg = {
            "content": last_msg.content,
            "datetime": f"{last_msg.datetime}+00:00"
        } if last_msg else "None"

        members = {}

        for member_user in db.session.query(ProjectChatGroupMemberLink) \
                .filter_by(project_chat_group_id=project_chat_group.id) \
                .join(User, User.id == ProjectChatGroupMemberLink.user_id) \
                .with_entities(User.id,
                               User.name,
                               User.small_avatar_url):

            members[member_user.id] = {
                "id": member_user.id,
                "name": member_user.name,
                "picUrl": member_user.small_avatar_url,
                "goToUrl": f"/{member_user.name}",
                "role": "default"
            }

        chats["projectChatGroup"][project_chat_group.id] = {
            "id":
            project_chat_group.id,
            "type":
            "projectChatGroup",
            "name":
            project_chat_group.name,
            "unreadCount":
            current_user.get_unread_count_in_chat(project_chat_group.id,
                                                  "projectChatGroup"),
            "lastMsg":
            last_msg,
            "picUrl":
            "/static/img/group.png",
            "roleOfCurrentUser":
            project_chat_group.user_role,
            "members":
            members
        }

    user_to_chat_with_name = request.args.get("with")

    if user_to_chat_with_name:
        member_user = User.get_by_name(user_to_chat_with_name)
        if member_user:
            if current_user.is_friend_with(member_user.id):
                return render_template(
                    "chat.html.j2",
                    chats=chats,
                    chat_to_open={
                        "id": User.get_by_name(user_to_chat_with_name).id,
                        "type": "userToUser"
                    })

    return render_template("chat.html.j2", chats=chats)
Beispiel #21
0
def signup():
    continue_to = request.args.get("continue")

    invalid_names_list = invalid_names()

    # -- POST
    if request.method == "POST":
        form = request.form

        valid = True

        lex, _ = get_lexicon_and_lang("signup_view_func")

        name_error_text = ""
        email_error_text = ""
        password_error_text = ""

        if User.query.filter(User.name.ilike(form['username'])).scalar(
        ) or form['username'] in invalid_names_list:
            name_error_text = lex["This username is not available"]
            valid = False

        if User.get_by_name_or_email(form['useremail']) \
                or User.query.filter_by(email_pending_verification=form['useremail']).scalar():
            email_error_text = lex["This email address is not available"]
            valid = False

        regexexp = re.compile("^[a-zA-Z][a-zA-Z0-9_-]*$")
        if not 3 <= len(form["username"]) <= 16 or not regexexp.search(
                form["username"]):
            name_error_text = lex["Invalid username"]
            valid = False

        if not 1 <= len(form["useremail"]) <= 32:
            email_error_text = lex["Invalid email address"]
            valid = False

        if not 8 <= len(form["password"]) <= 64:
            password_error_text = lex["Invalid password"]
            valid = False

        if not valid:
            return render_template("signup.html.j2",
                                   invalid_names=invalid_names_list,
                                   username=form["username"],
                                   useremail=form["useremail"],
                                   name_error_text=name_error_text,
                                   email_error_text=email_error_text,
                                   password_error_text=password_error_text)

        email_verification_case_id = uuid4().hex
        email_verification_code = token_urlsafe(16)[:8]

        if form.get("keepUserLoggedIn"):
            user = User(
                form["username"], form["useremail"],
                bcrypt.generate_password_hash(
                    form["password"]).decode("utf-8"),
                email_verification_case_id, email_verification_code, True)
            db.session.add(user)
            db.session.commit()
            login_user(user, True, timedelta(days=365))

        else:
            user = User(
                form["username"], form["useremail"],
                bcrypt.generate_password_hash(
                    form["password"]).decode("utf-8"),
                email_verification_case_id, email_verification_code, False)
            db.session.add(user)
            db.session.commit()
            login_user(user)

        verify_email_path = email_verification_case_id
        verify_email_path_with_code = verify_email_path

        if continue_to:
            verify_email_path += f"?continue={urllib.parse.quote(continue_to, safe='')}"
            verify_email_path_with_code = verify_email_path + f"&code={email_verification_code}"
        else:
            verify_email_path_with_code += f"?code={email_verification_code}"

        email_html = render_template(
            "email/account_created_verify_email.html.j2",
            username=user.name,
            email=user.email_pending_verification,
            code=email_verification_code,
            link="https://taskstack.org/verify-email/" +
            verify_email_path_with_code)

        email_txt = render_template(
            "email/account_created_verify_email.txt.j2",
            username=user.name,
            email=user.email_pending_verification,
            code=email_verification_code,
            link="https://taskstack.org/verify-email/" +
            verify_email_path_with_code)

        ses_cli.send_email(
            Source='*****@*****.**',
            Destination={'ToAddresses': [
                user.email_pending_verification,
            ]},
            Message={
                'Subject': {
                    'Data': lex['[Taskstack] Verify your email address'],
                    'Charset': 'UTF-8'
                },
                'Body': {
                    'Text': {
                        'Data': email_txt,
                        'Charset': 'UTF-8'
                    },
                    'Html': {
                        'Data': email_html,
                        'Charset': 'UTF-8'
                    }
                }
            })

        return redirect("/verify-email/" + verify_email_path)

    # -- GET
    if current_user.is_authenticated():
        return redirect("/")

    post_to = request.path

    if continue_to:
        post_to += "?continue=" + urllib.parse.quote(continue_to, safe="")

    return render_template(
        "signup.html.j2",
        post_to=post_to,
        invalid_names=invalid_names_list,
    )
Beispiel #22
0
def forgot_password():

    continue_to = request.args.get("continue")
    url_query_str = "?"
    if continue_to:
        url_query_str += "continue=" + urllib.parse.quote(continue_to, safe="")

    # -- POST
    if request.method == "POST":
        form = request.form

        user = User.get_by_name_or_email(form["name"])

        if not user:
            return render_template("forgot_password.html.j2",
                                   post_to=request.path + url_query_str,
                                   username_or_email_does_not_exist=True)

        user.reset_password_case_id = uuid4().hex
        reset_password_code = token_urlsafe(16)
        user.reset_password_code_hash = bcrypt.generate_password_hash(
            reset_password_code).decode("utf-8")

        db.session.commit()

        lex, _ = get_lexicon_and_lang("forgot_password_view_func")

        reset_password_path_with_code = user.reset_password_case_id + f"?code={reset_password_code}"

        email_html = render_template(
            "email/reset_password.html.j2",
            code=reset_password_code,
            link="https://taskstack.org/reset-password/" +
            reset_password_path_with_code)

        email_txt = render_template(
            "email/reset_password.txt.j2",
            code=reset_password_code,
            link="https://taskstack.org/reset-password/" +
            reset_password_path_with_code)

        ses_cli.send_email(Source='*****@*****.**',
                           Destination={'ToAddresses': [
                               user.email,
                           ]},
                           Message={
                               'Subject': {
                                   'Data': lex['[Taskstack] Reset password'],
                                   'Charset': 'UTF-8'
                               },
                               'Body': {
                                   'Text': {
                                       'Data': email_txt,
                                       'Charset': 'UTF-8'
                                   },
                                   'Html': {
                                       'Data': email_html,
                                       'Charset': 'UTF-8'
                                   }
                               }
                           })

        return redirect("/reset-password/" + user.reset_password_case_id +
                        url_query_str)

    # -- GET
    return render_template("forgot_password.html.j2",
                           post_to=request.path + url_query_str)