This commit is contained in:
parent
13ba5ebaed
commit
0240005ed1
|
@ -1,4 +1,6 @@
|
||||||
[0.2.16]
|
[0.2.16]
|
||||||
|
- resolvers: collab inviting logics
|
||||||
|
- orm: invite entity
|
||||||
- schema: Reaction.range -> Reaction.quote
|
- schema: Reaction.range -> Reaction.quote
|
||||||
- resolvers: queries and mutations revision and renaming
|
- resolvers: queries and mutations revision and renaming
|
||||||
- resolvers: delete_topic(slug) implemented
|
- resolvers: delete_topic(slug) implemented
|
||||||
|
|
25
orm/invite.py
Normal file
25
orm/invite.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from sqlalchemy import Column, ForeignKey, Enum
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from services.db import Base
|
||||||
|
from orm.author import Author
|
||||||
|
from orm.shout import Shout
|
||||||
|
from enum import Enum as Enumeration
|
||||||
|
|
||||||
|
|
||||||
|
class InviteStatus(Enumeration):
|
||||||
|
PENDING = 0
|
||||||
|
ACCEPTED = 1
|
||||||
|
REJECTED = 2
|
||||||
|
|
||||||
|
|
||||||
|
class Invite(Base):
|
||||||
|
__tablename__ = "invite"
|
||||||
|
|
||||||
|
inviter_id = Column(ForeignKey("author.id"), nullable=False, index=True)
|
||||||
|
invitee_id = Column(ForeignKey("author.id"), nullable=False, index=True)
|
||||||
|
shout_id = Column(ForeignKey("shout.id"), nullable=False, index=True)
|
||||||
|
status = Column(Enum(InviteStatus), default=InviteStatus.PENDING)
|
||||||
|
|
||||||
|
inviter = relationship(Author, foreign_keys=[inviter_id])
|
||||||
|
invitee = relationship(Author, foreign_keys=[invitee_id])
|
||||||
|
shout = relationship(Shout)
|
136
resolvers/collab.py
Normal file
136
resolvers/collab.py
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
from services.auth import login_required
|
||||||
|
from services.db import local_session
|
||||||
|
from services.schema import mutation
|
||||||
|
from orm.invite import Invite, InviteStatus
|
||||||
|
from orm.author import Author
|
||||||
|
from orm.shout import Shout
|
||||||
|
|
||||||
|
|
||||||
|
@mutation.field("accept_invite")
|
||||||
|
@login_required
|
||||||
|
async def accept_invite(_, info, invite_id: int):
|
||||||
|
user_id = info.context["user_id"]
|
||||||
|
|
||||||
|
# Check if the user exists
|
||||||
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if author:
|
||||||
|
# Check if the invite exists
|
||||||
|
invite = session.query(Invite).filter(Invite.id == invite_id).first()
|
||||||
|
if invite and invite.invitee_id == author.id and invite.status == InviteStatus.PENDING:
|
||||||
|
# Add the user to the shout authors
|
||||||
|
shout = session.query(Shout).filter(Shout.id == invite.shout_id).first()
|
||||||
|
if shout:
|
||||||
|
shout.authors.append(author)
|
||||||
|
session.delete(invite)
|
||||||
|
session.commit()
|
||||||
|
return {"success": True, "message": "Invite accepted"}
|
||||||
|
else:
|
||||||
|
return {"error": "Shout not found"}
|
||||||
|
else:
|
||||||
|
return {"error": "Invalid invite or already accepted/rejected"}
|
||||||
|
else:
|
||||||
|
return {"error": "User not found"}
|
||||||
|
|
||||||
|
|
||||||
|
@mutation.field("reject_invite")
|
||||||
|
@login_required
|
||||||
|
async def reject_invite(_, info, invite_id: int):
|
||||||
|
user_id = info.context["user_id"]
|
||||||
|
|
||||||
|
# Check if the user exists
|
||||||
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if author:
|
||||||
|
# Check if the invite exists
|
||||||
|
invite = session.query(Invite).filter(Invite.id == invite_id).first()
|
||||||
|
if invite and invite.invitee_id == author.id and invite.status == InviteStatus.PENDING:
|
||||||
|
# Delete the invite
|
||||||
|
session.delete(invite)
|
||||||
|
session.commit()
|
||||||
|
return {"success": True, "message": "Invite rejected"}
|
||||||
|
else:
|
||||||
|
return {"error": "Invalid invite or already accepted/rejected"}
|
||||||
|
else:
|
||||||
|
return {"error": "User not found"}
|
||||||
|
|
||||||
|
|
||||||
|
@mutation.field("create_invite")
|
||||||
|
@login_required
|
||||||
|
async def create_invite(_, info, slug: str = "", author_id: int = None, user: str = ""):
|
||||||
|
user_id = info.context["user_id"]
|
||||||
|
|
||||||
|
# Check if the inviter is the owner of the shout
|
||||||
|
with local_session() as session:
|
||||||
|
shout = session.query(Shout).filter(Shout.slug == slug).first()
|
||||||
|
if shout and shout.authors and user_id in [author.id for author in shout.authors]:
|
||||||
|
# Check if the invitee is a valid author
|
||||||
|
invitee = session.query(Author).filter(Author.id == author_id).first()
|
||||||
|
if invitee:
|
||||||
|
# Check if an invite already exists
|
||||||
|
existing_invite = (
|
||||||
|
session.query(Invite)
|
||||||
|
.filter(
|
||||||
|
Invite.inviter_id == user_id,
|
||||||
|
Invite.invitee_id == author_id,
|
||||||
|
Invite.shout_id == shout.id,
|
||||||
|
Invite.status == InviteStatus.PENDING,
|
||||||
|
)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
if existing_invite:
|
||||||
|
return {"error": "Invite already sent"}
|
||||||
|
|
||||||
|
# Create a new invite
|
||||||
|
new_invite = Invite(
|
||||||
|
inviter_id=user_id, invitee_id=author_id, shout_id=shout.id, status=InviteStatus.PENDING
|
||||||
|
)
|
||||||
|
session.add(new_invite)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return {"error": None, "invite": new_invite}
|
||||||
|
else:
|
||||||
|
return {"error": "Invalid invitee"}
|
||||||
|
else:
|
||||||
|
return {"error": "Access denied"}
|
||||||
|
|
||||||
|
|
||||||
|
@mutation.field("remove_author")
|
||||||
|
@login_required
|
||||||
|
async def remove_author(_, info, slug: str = "", author_id: int = None, user: str = ""):
|
||||||
|
user_id = info.context["user_id"]
|
||||||
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if author:
|
||||||
|
shout = session.query(Shout).filter(Shout.slug == slug).first()
|
||||||
|
# NOTE: owner should be first in a list
|
||||||
|
if shout and author.id == shout.authors.index(0):
|
||||||
|
shout.authors = [author for author in shout.authors if author.id != author_id]
|
||||||
|
session.commit()
|
||||||
|
return {}
|
||||||
|
return {"error": "Access denied"}
|
||||||
|
|
||||||
|
|
||||||
|
@mutation.field("remove_invite")
|
||||||
|
@login_required
|
||||||
|
async def remove_invite(_, info, invite_id: int):
|
||||||
|
user_id = info.context["user_id"]
|
||||||
|
|
||||||
|
# Check if the user exists
|
||||||
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if author:
|
||||||
|
# Check if the invite exists
|
||||||
|
invite = session.query(Invite).filter(Invite.id == invite_id).first()
|
||||||
|
shout = session.query(Shout).filter(Shout.id == invite.shout_id).first()
|
||||||
|
if shout and shout.deleted_at is None and invite:
|
||||||
|
if invite.inviter_id == author.id or author.id == shout.authors.index(0):
|
||||||
|
if invite.status == InviteStatus.PENDING:
|
||||||
|
# Delete the invite
|
||||||
|
session.delete(invite)
|
||||||
|
session.commit()
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
return {"error": "Invalid invite or already accepted/rejected"}
|
||||||
|
else:
|
||||||
|
return {"error": "Author not found"}
|
|
@ -313,6 +313,13 @@ type Mutation {
|
||||||
create_reaction(reaction: ReactionInput!): Result!
|
create_reaction(reaction: ReactionInput!): Result!
|
||||||
update_reaction(id: Int!, reaction: ReactionInput!): Result!
|
update_reaction(id: Int!, reaction: ReactionInput!): Result!
|
||||||
delete_reaction(id: Int!): Result!
|
delete_reaction(id: Int!): Result!
|
||||||
|
|
||||||
|
# collab
|
||||||
|
create_invite(slug: String, authorId: Int, user: String): Result!
|
||||||
|
remove_author(slug: String, authorId: Int, user: String): Result!
|
||||||
|
remove_invite(invite_id: Int!): Result!
|
||||||
|
accept_invite(invite_id: Int!): Result!
|
||||||
|
reject_invite(invite_id: Int!): Result!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -342,7 +349,7 @@ type Query {
|
||||||
|
|
||||||
# reader
|
# reader
|
||||||
get_shout(slug: String, shout_id: Int): Shout
|
get_shout(slug: String, shout_id: Int): Shout
|
||||||
load_shouts_followed(follower_id: Int!, limit: Int, offset: Int): [Shout]
|
load_shouts_followed(follower_id: Int!, limit: Int, offset: Int): [Shout] # userReactedShouts
|
||||||
load_shouts_by(options: LoadShoutsOptions): [Shout]
|
load_shouts_by(options: LoadShoutsOptions): [Shout]
|
||||||
load_shouts_search(text: String!, limit: Int, offset: Int): [Shout]
|
load_shouts_search(text: String!, limit: Int, offset: Int): [Shout]
|
||||||
load_shouts_feed(options: LoadShoutsOptions): [Shout]
|
load_shouts_feed(options: LoadShoutsOptions): [Shout]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user