import Collection from "@discordjs/collection";
import { NotificationType } from "../types/notification";
import { SnowflakeString } from "../types/snowflake";
import Animation, { BasicAnimation } from "./animation";
import Comment from "./comment";
import Message from "./message";
import Rating from "./rating";
import { RequestContext } from "./requestContext";
import Snowflake from "./snowflake";
import User from "./user";
import { DBNotification, DBNotificationAny, prisma } from "../../prisma";
/**
* Handles notification data
*/
class Notification {
id: Snowflake;
type: NotificationType;
user?: User;
animation?: BasicAnimation;
comment?: Comment;
rating?: Rating;
message?: Message;
constructor(data: {
id?: Snowflake,
type: NotificationType.USER_REGISTRATION,
user: User
});
constructor(data: {
id?: Snowflake,
type: NotificationType.USER_UPDATE,
user: User
});
constructor(data: {
id?: Snowflake,
type: NotificationType.ANIMATION_CREATE,
animation: Animation
});
constructor(data: {
id?: Snowflake,
type: NotificationType.ANIMATION_UPDATE,
animation: Animation
});
constructor(data: {
id?: Snowflake,
type: NotificationType.COMMENT_CREATE,
comment: Comment
});
constructor(data: {
id?: Snowflake,
type: NotificationType.COMMENT_EDIT,
comment: Comment
});
constructor(data: {
id?: Snowflake,
type: NotificationType.RATING_ADD,
rating: Rating
});
constructor(data: {
id?: Snowflake,
type: NotificationType.MESSAGE_RECEIVED,
message: Message
});
/**
* Creates new notification
* @param {any} data
*/
constructor(data: {
id?: Snowflake,
type: NotificationType,
user?: User,
animation?: BasicAnimation,
comment?: Comment,
rating?: Rating,
message?: Message
}) {
this.id = data.id || Snowflake.newSnowflake();
this.type = data.type;
this.user = data.user;
this.animation = data.animation;
this.comment = data.comment;
this.rating = data.rating;
this.message = data.message;
if(!this.user) {
if(this.animation) {
this.user = this.animation.author;
} else if(this.comment) {
this.user = this.comment.user;
} else if(this.rating) {
this.user = this.rating.user;
} else if(this.message) {
this.user = this.message.author;
}
}
if(!this.animation) {
if(this.comment) {
this.animation = this.comment.animation;
} else if(this.rating) {
this.animation = this.rating.animation;
}
}
}
/**
* @param {DBNotification | DBNotificationAny} data
* @param {RequestContext} ctx
*/
static async fromDatabase(data: DBNotification | DBNotificationAny, ctx: RequestContext) {
return new Notification({
id: new Snowflake(data.snowflake),
type: data.type,
user: "user" in data ? await User.fromDatabase(data.user, ctx) :
data.userId && await User.getUser(new Snowflake(data.userId), ctx),
animation: "animation" in data && data.animation ?
await Animation.fromDatabase(data.animation, ctx) :
data.animationId && await Animation.getAnimation(new Snowflake(data.animationId),
ctx),
comment: "comment" in data && data.comment ?
await Comment.fromDatabase(data.comment, ctx) :
data.commentId && await Comment.getComment(new Snowflake(data.commentId), ctx),
rating: "rating" in data && data.rating ?
await Rating.fromDatabase(data.rating, ctx) :
data.ratingId && await Rating.getRating(new Snowflake(data.ratingId), ctx),
// @ts-ignore overload thingies
message: !ctx.hasClient() ? undefined:
("message" in data && data.message ?
await Message.fromDatabase(data.message, ctx) :
data.messageId && await Message.getMessage(data.messageId.toString(), ctx))
});
}
/**
* Saves the notification into database
* @return {Promise<void>}
*/
async create(): Promise<void> {
await prisma.notification.create({
data: {
snowflake: this.id.toBigInt(),
userId: this.user?.id.toBigInt(),
animationId: this.animation?.id.toBigInt(),
commentId: this.comment?.id.toBigInt(),
ratingId: this.rating?.id.toBigInt(),
messageId: this.message?.id.toBigInt(),
type: this.type
}
});
}
/**
* Fetches data
* @param {any} data
* @param {RequestContext} ctx
*/
static async fetchData(data: any, ctx: RequestContext): Promise<{
user?: User,
animation?: BasicAnimation,
comment?: Comment,
rating?: Rating,
message?: Message
}> {
if(data.message && !ctx.hasClient()) {
throw new Error("User client is required for fetching messages");
}
return {
user: data.user && await User.getUser(data.user, ctx),
animation: data.animation && await Animation.getAnimation(data.animation, ctx),
comment: data.comment && await Comment.getComment(data.comment, ctx),
rating: data.rating && await Rating.getRating(data.rating, ctx),
// @ts-ignore checked by previous if
message: data.message && await Message.getMessage(data.message, ctx)
};
}
/**
* Returns public notifications for the home page
* @param {RequestContext} ctx
* @return {Promise<Collection<SnowflakeString, Notification>>}
*/
static async getPublicNotifications(ctx: RequestContext):
Promise<Collection<SnowflakeString, Notification>> {
const res = await prisma.notification.findMany({
where: {
type: {
not: NotificationType.MESSAGE_RECEIVED
}
},
orderBy: {
snowflake: "desc"
},
include: {
animation: true,
comment: true,
rating: true,
user: true
},
take: 10
});
const col = new Collection<SnowflakeString, Notification>();
for(var notif of res) {
col.set(notif.snowflake.toString(), await Notification.fromDatabase(notif, ctx));
}
return col;
}
/**
* Returns user specific notifications. If no user in context, returns public notifications
* @param {RequestContext} ctx
* @param {number} page
* @param {number} max
* @return {Promise<Collection<SnowflakeString, Notification>>}
*/
static async getUserNotifications(ctx: RequestContext, page?: number, max?: number):
Promise<Collection<SnowflakeString, Notification>> {
if(!ctx.hasClient()) {
return Notification.getPublicNotifications(ctx);
}
const res = await prisma.notification.findMany({
where: {
OR: [{
type: {
not: NotificationType.MESSAGE_RECEIVED
}
}, {
message: {
targetId: ctx.client.user.id.toBigInt()
}
}]
},
orderBy: {
snowflake: "desc"
},
include: {
animation: true,
comment: true,
message: true,
rating: true,
user: true
},
skip: page && max ? page * max : undefined,
take: max || 10
});
const col = new Collection<SnowflakeString, Notification>();
for(var notif of res) {
col.set(notif.snowflake.toString(), await Notification.fromDatabase(notif, ctx));
}
return col;
}
/**
* Returns JSON compatible representation
* @return {any}
*/
toJSON(): any {
return {
id: this.id.toString(),
date: this.id.time,
type: this.type,
user: this.user?.toJSON(),
animation: this.animation?.toJSON(),
comment: this.comment?.toJSON(),
rating: this.rating?.toJSON(),
message: this.message?.toJSON()
};
}
}
export default Notification;
Source