Merge pull request #87 from Discours/feature/migration_fix_and_notification_schema

Migration fix, notification schema update
This commit is contained in:
Ilya Y 2023-10-09 13:54:12 +03:00 committed by GitHub
commit ca77f6c5fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 328 additions and 304 deletions

View File

@ -70,7 +70,6 @@ def create_author_from_app(app):
"username": app["email"], "username": app["email"],
"email": app["email"], "email": app["email"],
"name": app.get("name", ""), "name": app.get("name", ""),
"bio": app.get("bio", ""),
"emailConfirmed": False, "emailConfirmed": False,
"slug": slug, "slug": slug,
"createdAt": ts, "createdAt": ts,
@ -149,6 +148,7 @@ async def migrate(entry, storage):
"deletedAt": date_parse(entry.get("deletedAt")) if entry.get("deletedAt") else None, "deletedAt": date_parse(entry.get("deletedAt")) if entry.get("deletedAt") else None,
"createdAt": date_parse(entry.get("createdAt", OLD_DATE)), "createdAt": date_parse(entry.get("createdAt", OLD_DATE)),
"updatedAt": date_parse(entry["updatedAt"]) if "updatedAt" in entry else ts, "updatedAt": date_parse(entry["updatedAt"]) if "updatedAt" in entry else ts,
"createdBy": author.id,
"topics": await add_topics_follower(entry, storage, author), "topics": await add_topics_follower(entry, storage, author),
"body": extract_html(entry, cleanup=True) "body": extract_html(entry, cleanup=True)
} }

View File

@ -21,7 +21,6 @@ def migrate(entry):
"createdAt": parse(entry["createdAt"]), "createdAt": parse(entry["createdAt"]),
"emailConfirmed": ("@discours.io" in email) or bool(entry["emails"][0]["verified"]), "emailConfirmed": ("@discours.io" in email) or bool(entry["emails"][0]["verified"]),
"muted": False, # amnesty "muted": False, # amnesty
"bio": entry["profile"].get("bio", ""),
"links": [], "links": [],
"name": "anonymous", "name": "anonymous",
"password": entry["services"]["password"].get("bcrypt") "password": entry["services"]["password"].get("bcrypt")
@ -29,7 +28,7 @@ def migrate(entry):
if "updatedAt" in entry: if "updatedAt" in entry:
user_dict["updatedAt"] = parse(entry["updatedAt"]) user_dict["updatedAt"] = parse(entry["updatedAt"])
if "wasOnineAt" in entry: if "wasOnlineAt" in entry:
user_dict["lastSeen"] = parse(entry["wasOnlineAt"]) user_dict["lastSeen"] = parse(entry["wasOnlineAt"])
if entry.get("profile"): if entry.get("profile"):
# slug # slug

View File

@ -1,13 +1,22 @@
from datetime import datetime from datetime import datetime
from sqlalchemy import Column, String, JSON, ForeignKey, DateTime, Boolean from sqlalchemy import Column, Enum, JSON, ForeignKey, DateTime, Boolean, Integer
from base.orm import Base from base.orm import Base
from enum import Enum as Enumeration
class NotificationType(Enumeration):
NEW_COMMENT = 1
NEW_REPLY = 2
class Notification(Base): class Notification(Base):
__tablename__ = "notification" __tablename__ = "notification"
shout = Column(ForeignKey("shout.id"), index=True)
reaction = Column(ForeignKey("reaction.id"), index=True)
user = Column(ForeignKey("user.id"), index=True) user = Column(ForeignKey("user.id"), index=True)
createdAt = Column(DateTime, nullable=False, default=datetime.now, index=True) createdAt = Column(DateTime, nullable=False, default=datetime.now, index=True)
seen = Column(Boolean, nullable=False, default=False, index=True) seen = Column(Boolean, nullable=False, default=False, index=True)
type = Column(String, nullable=False) type = Column(Enum(NotificationType), nullable=False)
data = Column(JSON, nullable=True) data = Column(JSON, nullable=True)
occurrences = Column(Integer, default=1)

View File

@ -3,24 +3,24 @@ scalar DateTime
################################### Payload ################################### ################################### Payload ###################################
enum MessageStatus { enum MessageStatus {
NEW NEW
UPDATED UPDATED
DELETED DELETED
} }
type UserFollowings { type UserFollowings {
unread: Int unread: Int
topics: [String] topics: [String]
authors: [String] authors: [String]
reactions: [Int] reactions: [Int]
communities: [String] communities: [String]
} }
type AuthResult { type AuthResult {
error: String error: String
token: String token: String
user: User user: User
news: UserFollowings news: UserFollowings
} }
type ChatMember { type ChatMember {
@ -60,84 +60,84 @@ type Author {
} }
type Result { type Result {
error: String error: String
slugs: [String] slugs: [String]
chat: Chat chat: Chat
chats: [Chat] chats: [Chat]
message: Message message: Message
messages: [Message] messages: [Message]
members: [ChatMember] members: [ChatMember]
shout: Shout shout: Shout
shouts: [Shout] shouts: [Shout]
author: Author author: Author
authors: [Author] authors: [Author]
reaction: Reaction reaction: Reaction
reactions: [Reaction] reactions: [Reaction]
topic: Topic topic: Topic
topics: [Topic] topics: [Topic]
community: Community community: Community
communities: [Community] communities: [Community]
} }
enum ReactionStatus { enum ReactionStatus {
NEW NEW
UPDATED UPDATED
CHANGED CHANGED
EXPLAINED EXPLAINED
DELETED DELETED
} }
type ReactionUpdating { type ReactionUpdating {
error: String error: String
status: ReactionStatus status: ReactionStatus
reaction: Reaction reaction: Reaction
} }
################################### Inputs ################################### ################################### Inputs ###################################
input ShoutInput { input ShoutInput {
slug: String slug: String
title: String title: String
body: String body: String
lead: String lead: String
description: String description: String
layout: String layout: String
media: String media: String
authors: [String] authors: [String]
topics: [TopicInput] topics: [TopicInput]
community: Int community: Int
mainTopic: TopicInput mainTopic: TopicInput
subtitle: String subtitle: String
cover: String cover: String
} }
input ProfileInput { input ProfileInput {
slug: String slug: String
name: String name: String
userpic: String userpic: String
links: [String] links: [String]
bio: String bio: String
about: String about: String
} }
input TopicInput { input TopicInput {
id: Int, id: Int,
slug: String! slug: String!
# community: String! # community: String!
title: String title: String
body: String body: String
pic: String pic: String
# children: [String] # children: [String]
# parents: [String] # parents: [String]
} }
input ReactionInput { input ReactionInput {
kind: ReactionKind! kind: ReactionKind!
shout: Int! shout: Int!
range: String range: String
body: String body: String
replyTo: Int replyTo: Int
} }
input ChatInput { input ChatInput {
@ -147,55 +147,55 @@ input ChatInput {
} }
enum FollowingEntity { enum FollowingEntity {
TOPIC TOPIC
AUTHOR AUTHOR
COMMUNITY COMMUNITY
REACTIONS REACTIONS
} }
################################### Mutation ################################### Mutation
type Mutation { type Mutation {
# inbox # inbox
createChat(title: String, members: [Int]!): Result! createChat(title: String, members: [Int]!): Result!
updateChat(chat: ChatInput!): Result! updateChat(chat: ChatInput!): Result!
deleteChat(chatId: String!): Result! deleteChat(chatId: String!): Result!
createMessage(chat: String!, body: String!, replyTo: Int): Result! createMessage(chat: String!, body: String!, replyTo: Int): Result!
updateMessage(chatId: String!, id: Int!, body: String!): Result! updateMessage(chatId: String!, id: Int!, body: String!): Result!
deleteMessage(chatId: String!, id: Int!): Result! deleteMessage(chatId: String!, id: Int!): Result!
markAsRead(chatId: String!, ids: [Int]!): Result! markAsRead(chatId: String!, ids: [Int]!): Result!
# auth # auth
getSession: AuthResult! getSession: AuthResult!
registerUser(email: String!, password: String, name: String): AuthResult! registerUser(email: String!, password: String, name: String): AuthResult!
sendLink(email: String!, lang: String, template: String): Result! sendLink(email: String!, lang: String, template: String): Result!
confirmEmail(token: String!): AuthResult! confirmEmail(token: String!): AuthResult!
# shout # shout
createShout(inp: ShoutInput!): Result! createShout(inp: ShoutInput!): Result!
updateShout(shout_id: Int!, shout_input: ShoutInput, publish: Boolean): Result! updateShout(shout_id: Int!, shout_input: ShoutInput, publish: Boolean): Result!
deleteShout(shout_id: Int!): Result! deleteShout(shout_id: Int!): Result!
# user profile # user profile
rateUser(slug: String!, value: Int!): Result! rateUser(slug: String!, value: Int!): Result!
updateOnlineStatus: Result! updateOnlineStatus: Result!
updateProfile(profile: ProfileInput!): Result! updateProfile(profile: ProfileInput!): Result!
# topics # topics
createTopic(input: TopicInput!): Result! createTopic(input: TopicInput!): Result!
# TODO: mergeTopics(t1: String!, t2: String!): Result! # TODO: mergeTopics(t1: String!, t2: String!): Result!
updateTopic(input: TopicInput!): Result! updateTopic(input: TopicInput!): Result!
destroyTopic(slug: String!): Result! destroyTopic(slug: String!): Result!
# reactions # reactions
createReaction(reaction: ReactionInput!): Result! createReaction(reaction: ReactionInput!): Result!
updateReaction(id: Int!, reaction: ReactionInput!): Result! updateReaction(id: Int!, reaction: ReactionInput!): Result!
deleteReaction(id: Int!): Result! deleteReaction(id: Int!): Result!
# following # following
follow(what: FollowingEntity!, slug: String!): Result! follow(what: FollowingEntity!, slug: String!): Result!
unfollow(what: FollowingEntity!, slug: String!): Result! unfollow(what: FollowingEntity!, slug: String!): Result!
} }
input MessagesBy { input MessagesBy {
@ -219,24 +219,24 @@ input AuthorsBy {
} }
input LoadShoutsFilters { input LoadShoutsFilters {
title: String title: String
body: String body: String
topic: String topic: String
author: String author: String
layout: String layout: String
excludeLayout: String excludeLayout: String
visibility: String visibility: String
days: Int days: Int
reacted: Boolean reacted: Boolean
} }
input LoadShoutsOptions { input LoadShoutsOptions {
filters: LoadShoutsFilters filters: LoadShoutsFilters
with_author_captions: Boolean with_author_captions: Boolean
limit: Int! limit: Int!
offset: Int offset: Int
order_by: String order_by: String
order_by_desc: Boolean order_by_desc: Boolean
} }
input ReactionBy { input ReactionBy {
@ -252,251 +252,267 @@ input ReactionBy {
################################### Query ################################### Query
type Query { type Query {
# inbox # inbox
loadChats( limit: Int, offset: Int): Result! # your chats loadChats( limit: Int, offset: Int): Result! # your chats
loadMessagesBy(by: MessagesBy!, limit: Int, offset: Int): Result! loadMessagesBy(by: MessagesBy!, limit: Int, offset: Int): Result!
loadRecipients(limit: Int, offset: Int): Result! loadRecipients(limit: Int, offset: Int): Result!
searchRecipients(query: String!, limit: Int, offset: Int): Result! searchRecipients(query: String!, limit: Int, offset: Int): Result!
searchMessages(by: MessagesBy!, limit: Int, offset: Int): Result! searchMessages(by: MessagesBy!, limit: Int, offset: Int): Result!
# auth # auth
isEmailUsed(email: String!): Boolean! isEmailUsed(email: String!): Boolean!
signIn(email: String!, password: String, lang: String): AuthResult! signIn(email: String!, password: String, lang: String): AuthResult!
signOut: AuthResult! signOut: AuthResult!
# zine # zine
loadAuthorsBy(by: AuthorsBy, limit: Int, offset: Int): [Author]! loadAuthorsBy(by: AuthorsBy, limit: Int, offset: Int): [Author]!
loadShout(slug: String, shout_id: Int): Shout loadShout(slug: String, shout_id: Int): Shout
loadShouts(options: LoadShoutsOptions): [Shout]! loadShouts(options: LoadShoutsOptions): [Shout]!
loadDrafts: [Shout]! loadDrafts: [Shout]!
loadReactionsBy(by: ReactionBy!, limit: Int, offset: Int): [Reaction]! loadReactionsBy(by: ReactionBy!, limit: Int, offset: Int): [Reaction]!
userFollowers(slug: String!): [Author]! userFollowers(slug: String!): [Author]!
userFollowedAuthors(slug: String!): [Author]! userFollowedAuthors(slug: String!): [Author]!
userFollowedTopics(slug: String!): [Topic]! userFollowedTopics(slug: String!): [Topic]!
authorsAll: [Author]! authorsAll: [Author]!
getAuthor(slug: String!): Author getAuthor(slug: String!): Author
myFeed(options: LoadShoutsOptions): [Shout] myFeed(options: LoadShoutsOptions): [Shout]
# migrate # migrate
markdownBody(body: String!): String! markdownBody(body: String!): String!
# topics # topics
getTopic(slug: String!): Topic getTopic(slug: String!): Topic
topicsAll: [Topic]! topicsAll: [Topic]!
topicsRandom(amount: Int): [Topic]! topicsRandom(amount: Int): [Topic]!
topicsByCommunity(community: String!): [Topic]! topicsByCommunity(community: String!): [Topic]!
topicsByAuthor(author: String!): [Topic]! topicsByAuthor(author: String!): [Topic]!
} }
############################################ Subscription ############################################ Subscription
type Subscription { type Subscription {
newMessage: Message # new messages in inbox newMessage: Message # new messages in inbox
newShout: Shout # personal feed new shout newShout: Shout # personal feed new shout
newReaction: Reaction # new reactions to notify newReaction: Reaction # new reactions to notify
} }
############################################ Entities ############################################ Entities
type Resource { type Resource {
id: Int! id: Int!
name: String! name: String!
} }
type Operation { type Operation {
id: Int! id: Int!
name: String! name: String!
} }
type Permission { type Permission {
operation: Int! operation: Int!
resource: Int! resource: Int!
} }
type Role { type Role {
id: Int! id: Int!
name: String! name: String!
community: String! community: String!
desc: String desc: String
permissions: [Permission!]! permissions: [Permission!]!
} }
type Rating { type Rating {
rater: String! rater: String!
value: Int! value: Int!
} }
type User { type User {
id: Int! id: Int!
username: String! # to login, ex. email, phone username: String! # to login, ex. email, phone
createdAt: DateTime! createdAt: DateTime!
lastSeen: DateTime lastSeen: DateTime
slug: String! slug: String!
name: String # to display name: String # to display
email: String email: String
password: String password: String
oauth: String # provider:token oauth: String # provider:token
userpic: String userpic: String
links: [String] links: [String]
emailConfirmed: Boolean # should contain all emails too emailConfirmed: Boolean # should contain all emails too
muted: Boolean muted: Boolean
updatedAt: DateTime updatedAt: DateTime
ratings: [Rating] ratings: [Rating]
bio: String bio: String
about: String about: String
communities: [Int] # user participating communities communities: [Int] # user participating communities
oid: String oid: String
} }
enum ReactionKind { enum ReactionKind {
LIKE LIKE
DISLIKE DISLIKE
AGREE AGREE
DISAGREE DISAGREE
PROOF PROOF
DISPROOF DISPROOF
COMMENT COMMENT
QUOTE QUOTE
PROPOSE PROPOSE
ASK ASK
REMARK REMARK
FOOTNOTE FOOTNOTE
ACCEPT ACCEPT
REJECT REJECT
} }
type Reaction { type Reaction {
id: Int! id: Int!
shout: Shout! shout: Shout!
createdAt: DateTime! createdAt: DateTime!
createdBy: User! createdBy: User!
updatedAt: DateTime updatedAt: DateTime
deletedAt: DateTime deletedAt: DateTime
deletedBy: User deletedBy: User
range: String # full / 0:2340 range: String # full / 0:2340
kind: ReactionKind! kind: ReactionKind!
body: String body: String
replyTo: Int replyTo: Int
stat: Stat stat: Stat
old_id: String old_id: String
old_thread: String old_thread: String
} }
# is publication # is publication
type Shout { type Shout {
id: Int! id: Int!
slug: String! slug: String!
body: String! body: String!
lead: String lead: String
description: String description: String
createdAt: DateTime! createdAt: DateTime!
topics: [Topic] topics: [Topic]
mainTopic: String mainTopic: String
title: String title: String
subtitle: String subtitle: String
authors: [Author] authors: [Author]
lang: String lang: String
community: String community: String
cover: String cover: String
layout: String # audio video literature image layout: String # audio video literature image
versionOf: String # for translations and re-telling the same story versionOf: String # for translations and re-telling the same story
visibility: String # owner authors community public visibility: String # owner authors community public
updatedAt: DateTime updatedAt: DateTime
updatedBy: User updatedBy: User
deletedAt: DateTime deletedAt: DateTime
deletedBy: User deletedBy: User
publishedAt: DateTime publishedAt: DateTime
media: String # json [ { title pic url body }, .. ] media: String # json [ { title pic url body }, .. ]
stat: Stat stat: Stat
} }
type Stat { type Stat {
viewed: Int viewed: Int
reacted: Int reacted: Int
rating: Int rating: Int
commented: Int commented: Int
ranking: Int ranking: Int
} }
type Community { type Community {
id: Int! id: Int!
slug: String! slug: String!
name: String! name: String!
desc: String desc: String
pic: String! pic: String!
createdAt: DateTime! createdAt: DateTime!
createdBy: User! createdBy: User!
} }
type Collection { type Collection {
id: Int! id: Int!
slug: String! slug: String!
title: String! title: String!
desc: String desc: String
amount: Int amount: Int
publishedAt: DateTime publishedAt: DateTime
createdAt: DateTime! createdAt: DateTime!
createdBy: User! createdBy: User!
} }
type TopicStat { type TopicStat {
shouts: Int! shouts: Int!
followers: Int! followers: Int!
authors: Int! authors: Int!
# viewed: Int # viewed: Int
# reacted: Int! # reacted: Int!
# commented: Int # commented: Int
# rating: Int # rating: Int
} }
type Topic { type Topic {
id: Int! id: Int!
slug: String! slug: String!
title: String title: String
body: String body: String
pic: String pic: String
# community: Community! # community: Community!
stat: TopicStat stat: TopicStat
oid: String oid: String
} }
type Token { type Token {
createdAt: DateTime! createdAt: DateTime!
expiresAt: DateTime expiresAt: DateTime
id: Int! id: Int!
ownerId: Int! ownerId: Int!
usedAt: DateTime usedAt: DateTime
value: String! value: String!
} }
type Message { type Message {
author: Int! author: Int!
chatId: String! chatId: String!
body: String! body: String!
createdAt: Int! createdAt: Int!
id: Int! id: Int!
replyTo: Int replyTo: Int
updatedAt: Int updatedAt: Int
seen: Boolean seen: Boolean
} }
type Chat { type Chat {
id: String! id: String!
createdAt: Int! createdAt: Int!
createdBy: Int! createdBy: Int!
updatedAt: Int! updatedAt: Int!
title: String title: String
description: String description: String
users: [Int] users: [Int]
members: [ChatMember] members: [ChatMember]
admins: [Int] admins: [Int]
messages: [Message] messages: [Message]
unread: Int unread: Int
private: Boolean private: Boolean
}
enum NotificationType {
NEW_COMMENT,
NEW_REPLY
}
type Notification {
id: Int!
shout: Int
reaction: Int
type: NotificationType
createdAt: DateTime!
seen: Boolean!
data: String # JSON
occurrences: Int!
} }