Add level configuration and query

- Add query getLevels to get all possible levels
- Add mutation createLevel as a way for admins to create new levels
- Remove column levelNumber and replace it with method that looks up the number of the level by counting
pull/4/head
trivernis 5 years ago
parent 9328367bb5
commit e8eb85993e

@ -98,7 +98,7 @@ export class UploadManager {
* @param extension * @param extension
*/ */
public async processAndStoreVideo(data: Buffer, extension: string): Promise<Media> { public async processAndStoreVideo(data: Buffer, extension: string): Promise<Media> {
const fileBasename = UploadManager.getCrypticFileName() + extension; const fileBasename = UploadManager.getCrypticFileName() + "." + extension;
await fsx.ensureDir(this.dataDir); await fsx.ensureDir(this.dataDir);
const filePath = path.join(this.dataDir, fileBasename); const filePath = path.join(this.dataDir, fileBasename);
await fsx.writeFile(filePath, data); await fsx.writeFile(filePath, data);

@ -0,0 +1,10 @@
import {BaseError} from "./BaseError";
/**
* An error that is thrown when the level already exists
*/
export class LevelAlreadyExistsError extends BaseError {
constructor(property: string) {
super(`A level with the property value '${property}' already exists`);
}
}

@ -16,18 +16,17 @@ export class Level extends Model<Level> {
public name: string; public name: string;
/** /**
* The number of the level * The required points for the level
*/ */
@NotNull @NotNull
@Unique @Unique
@Column({allowNull: false, unique: true}) @Column({allowNull: false, unique: true})
public levelNumber: number; public points: number;
/** /**
* The required points for the level * Returns the number of the level as the number of the database entry
*/ */
@NotNull public async levelNumber(): Promise<number> {
@Unique return Level.count({where: {points: {[sqz.Op.lte]: this.points}}});
@Column({allowNull: false, unique: true}) }
public points: number;
} }

@ -44,7 +44,7 @@ export class User extends Model<User> {
*/ */
@BeforeUpdate @BeforeUpdate
public static async assignLevel(instance: User) { public static async assignLevel(instance: User) {
const level = await Level.findOne({where: {points: {[sqz.Op.lte]: instance.rankpoints}}, order: [["levelNumber", "desc"]]}) as Level; const level = await Level.findOne({where: {points: {[sqz.Op.lte]: instance.rankpoints}}, order: [["points", "desc"]]}) as Level;
if (level) { if (level) {
instance.$set("rLevel", level); instance.$set("rLevel", level);
} }

@ -1,11 +1,13 @@
import {GraphQLError} from "graphql"; import {GraphQLError} from "graphql";
import * as yaml from "js-yaml"; import * as yaml from "js-yaml";
import sequelize from "sequelize";
import isEmail from "validator/lib/isEmail"; import isEmail from "validator/lib/isEmail";
import dataAccess from "../../lib/dataAccess"; import dataAccess from "../../lib/dataAccess";
import {BlacklistedError} from "../../lib/errors/BlacklistedError"; import {BlacklistedError} from "../../lib/errors/BlacklistedError";
import {GroupNotFoundError} from "../../lib/errors/GroupNotFoundError"; import {GroupNotFoundError} from "../../lib/errors/GroupNotFoundError";
import {HandleInUseError} from "../../lib/errors/HandleInUseError"; import {HandleInUseError} from "../../lib/errors/HandleInUseError";
import {InvalidEmailError} from "../../lib/errors/InvalidEmailError"; import {InvalidEmailError} from "../../lib/errors/InvalidEmailError";
import {LevelAlreadyExistsError} from "../../lib/errors/LevelAlreadyExistsError";
import {NotAGroupAdminError} from "../../lib/errors/NotAGroupAdminError"; import {NotAGroupAdminError} from "../../lib/errors/NotAGroupAdminError";
import {NotAnAdminError} from "../../lib/errors/NotAnAdminError"; import {NotAnAdminError} from "../../lib/errors/NotAnAdminError";
import {NotTheGroupCreatorError} from "../../lib/errors/NotTheGroupCreatorError"; import {NotTheGroupCreatorError} from "../../lib/errors/NotTheGroupCreatorError";
@ -15,7 +17,18 @@ import {ReportReasonNameAlreadyExistsError} from "../../lib/errors/ReportReasonN
import {ReportReasonNotFoundError} from "../../lib/errors/ReportReasonNotFoundError"; import {ReportReasonNotFoundError} from "../../lib/errors/ReportReasonNotFoundError";
import globals from "../../lib/globals"; import globals from "../../lib/globals";
import {InternalEvents} from "../../lib/InternalEvents"; import {InternalEvents} from "../../lib/InternalEvents";
import {Activity, BlacklistedPhrase, ChatMessage, ChatRoom, Event, Group, Post, Request, User} from "../../lib/models"; import {
Activity,
BlacklistedPhrase,
ChatMessage,
ChatRoom,
Event,
Group,
Level,
Post,
Request,
User,
} from "../../lib/models";
import {Report} from "../../lib/models"; import {Report} from "../../lib/models";
import {ReportReason} from "../../lib/models"; import {ReportReason} from "../../lib/models";
import {UploadManager} from "../../lib/UploadManager"; import {UploadManager} from "../../lib/UploadManager";
@ -147,6 +160,8 @@ export class MutationResolver extends BaseResolver {
await user.save(); await user.save();
return user.settings; return user.settings;
} catch (err) { } catch (err) {
globals.logger.warning(err.message);
globals.logger.debug(err.stack);
throw new GraphQLError("Invalid settings json."); throw new GraphQLError("Invalid settings json.");
} }
} }
@ -557,4 +572,26 @@ export class MutationResolver extends BaseResolver {
} }
return ReportReason.create({name, description}); return ReportReason.create({name, description});
} }
/**
* Creates a new level
* @param name
* @param levelNumber
* @param requiredPoints
* @param request
*/
public async createLevel({name, requiredPoints}: {name: string, requiredPoints: number}, request: any):
Promise<Level> {
this.ensureLoggedIn(request);
const user = await User.findByPk(request.session.userId);
if (!user.isAdmin) {
throw new NotAnAdminError();
}
const existingLevel = await Level.findOne({where: {[sequelize.Op.or]: [{name}, {points: requiredPoints}]}});
if (existingLevel) {
throw new LevelAlreadyExistsError(
existingLevel.name === name ? "name" : "points");
}
return Level.create({name, points: requiredPoints});
}
} }

@ -7,7 +7,18 @@ import {GroupNotFoundError} from "../../lib/errors/GroupNotFoundError";
import {NotAnAdminError} from "../../lib/errors/NotAnAdminError"; import {NotAnAdminError} from "../../lib/errors/NotAnAdminError";
import {RequestNotFoundError} from "../../lib/errors/RequestNotFoundError"; import {RequestNotFoundError} from "../../lib/errors/RequestNotFoundError";
import {UserNotFoundError} from "../../lib/errors/UserNotFoundError"; import {UserNotFoundError} from "../../lib/errors/UserNotFoundError";
import {Activity, BlacklistedPhrase, ChatRoom, Event, Group, Post, Report, Request, User} from "../../lib/models"; import {
Activity,
BlacklistedPhrase,
ChatRoom,
Event,
Group,
Level,
Post,
Report,
Request,
User
} from "../../lib/models";
import {BlacklistedResult} from "./BlacklistedResult"; import {BlacklistedResult} from "./BlacklistedResult";
import {MutationResolver} from "./MutationResolver"; import {MutationResolver} from "./MutationResolver";
import {SearchResult} from "./SearchResult"; import {SearchResult} from "./SearchResult";
@ -198,6 +209,15 @@ export class QueryResolver extends MutationResolver {
if (!user?.isAdmin) { if (!user?.isAdmin) {
throw new NotAnAdminError(); throw new NotAnAdminError();
} }
return Report.findAll({limit: first, offset}); return Report.findAll({limit: first, offset, order: [["id", "DESC"]]});
}
/**
* Returns the levels that are configured
* @param first
* @param offset
*/
public async getLevels({first, offset}: {first: number, offset: number}): Promise<Level[]> {
return Level.findAll({limit: first, offset, order: [["points", "ASC"]]});
} }
} }

@ -48,6 +48,9 @@ type Query {
"Returns all issued reports with pagination" "Returns all issued reports with pagination"
getReports(first: Int = 20, offset: Int = 0): [Report!]! @complexity(value: 1, multipliers: ["first"]) getReports(first: Int = 20, offset: Int = 0): [Report!]! @complexity(value: 1, multipliers: ["first"])
"Returns the levels configured in the backend"
getLevels(first: Int =20, offset: Int = 0): [Level!]! @complexity(value: 1, multipliers: ["first"])
} }
type Mutation { type Mutation {
@ -143,6 +146,9 @@ type Mutation {
"Creates a new report reason" "Creates a new report reason"
createReportReason(name: String!, description: String!): ReportReason createReportReason(name: String!, description: String!): ReportReason
"Creates a new level"
createLevel(name: String!, requiredPoints: Int!): Level!
} }
interface UserData { interface UserData {
@ -574,11 +580,17 @@ type ReportReason {
"A level of a user" "A level of a user"
type Level { type Level {
"The level id"
id: ID!
"The name of the level" "The name of the level"
name: String! name: String!
"The number of the level in the ranking" "The number of the level in the ranking"
levelNumber: String! levelNumber: Int!
"The points required for this level"
points: Int!
} }
"represents the type of media" "represents the type of media"

Loading…
Cancel
Save