cron#CronJob TypeScript Examples

The following examples show how to use cron#CronJob. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: db-stats.ts    From discord with GNU General Public License v3.0 6 votes vote down vote up
public static startMonitoring(bot: FreeStuffBot) {
    new CronJob('0 0 0 * * *', () => {
      setTimeout(async () => {
        const guildCount = bot.guilds.cache.size
        const guildMemberCount = [ ...bot.guilds.cache.values() ].reduce((count, g) => count + g.memberCount, 0)

        Logger.process(`Updated Stats. Guilds: ${bot.guilds.cache.size}; Members: ${guildMemberCount}; Shards ${bot.options.shards}`)
        ;(await this.usage).guilds.updateYesterday(guildCount, true)
        ;(await this.usage).members.updateYesterday(guildMemberCount, true)

        this.updateTopClients()
      }, 60000)
    }).start()

    bot.on('ready', this.updateTopClients)
  }
Example #2
Source File: ScheduleTimeTask.ts    From guardian with Apache License 2.0 6 votes vote down vote up
async start<T extends BaseSubstrateGuardian>(guardian: T) {
    await guardian.isReady();

    const { cronTime } = this.arguments;

    return new Observable<Output>((subscriber) => {
      const job = new CronJob(
        cronTime,
        () => {
          subscriber.next({
            current: +new Date(),
            next: +job.nextDate()
          });
        },
        () => {
          subscriber.complete();
        },
        true
      );

      return () => {
        job.stop();
      };
    });
  }
Example #3
Source File: app.service.ts    From runebot with MIT License 6 votes vote down vote up
constructor(
    protected readonly configService: AppConfigService,
    private readonly _discord: DiscordService,
    private readonly _schedulerRegistry: SchedulerRegistry, //private readonly _twitter: TwitterService, //private readonly _ethereum: EthereumService,
  ) {
    const salesChecker = new CronJob(
      this.configService.bot.salesCheckCron,
      async () => {
        this._logger.log(`Running Sales Checker Job`);
        this._discord.checkSales([
          this.configService.wizard,
          this.configService.soul,
          this.configService.warrior,
          this.configService.pony,
          this.configService.flame,
          this.configService.lock,
          this.configService.beast,
          this.configService.spawn,
        ]);
      },
    );

    this._schedulerRegistry.addCronJob(CronJobs.SALES_CHECKER, salesChecker);
    salesChecker.start();
    this._logger.log(
      `Sales checker cron job started. Cron pattern: ${this.configService.bot.salesCheckCron}`,
    );
  }
Example #4
Source File: scheduler.ts    From amplication with Apache License 2.0 6 votes vote down vote up
// getting after npm run build:generate-types from config.schema.json

export function createJob(config: Config): CronJob {
  return new CronJob(
    config.schedule,
    () =>
      fetch(config.request.url, config.request)
        .then((res) => {
          const { method = "GET" } = config.request;
          const log = `${method} ${config.request.url} - ${res.status}`;
          console.info(log);
        })
        .catch((error) => {
          console.error(error.message);
        }),
    null,
    true,
    config.timezone
  );
}
Example #5
Source File: pushNotifications.ts    From vsinder with Apache License 2.0 6 votes vote down vote up
startPushNotificationRunner = () => {
  const expo = new Expo();

  // every minute
  new CronJob(
    "0 * * * * *",
    async () => {
      if (!messages.length) {
        return;
      }
      const tmpMessages = [...messages];
      messages = [];
      const chunks = expo.chunkPushNotifications(
        await messagesToExpoMessages(tmpMessages)
      );
      for (let chunk of chunks) {
        try {
          let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
          ticketChunk.forEach((x) => {
            if (x.status === "error") {
              console.error(x);
            }
          });
          // @todo
          // NOTE: If a ticket contains an error code in ticket.details.error, you
          // must handle it appropriately. The error codes are listed in the Expo
          // documentation:
          // https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
        } catch (error) {
          console.error(error);
        }
      }
    },
    null,
    true,
    "America/Chicago"
  );
}
Example #6
Source File: resetNumSwipesDaily.ts    From vsinder with Apache License 2.0 6 votes vote down vote up
resetNumSwipesDaily = () => {
  // every minute
  new CronJob(
    "0 1 * * * *",
    async () => {
      try {
        await User.update({}, { numSwipesToday: 0 });
      } catch (err) {
        console.log("error resetNumSwipesDaily ", err);
      }
    },
    null,
    true,
    "America/Chicago"
  );
}
Example #7
Source File: resetNumSwipesDaily.ts    From vsinder-api with Apache License 2.0 6 votes vote down vote up
resetNumSwipesDaily = () => {
  // every minute
  new CronJob(
    "0 1 * * * *",
    async () => {
      try {
        await User.update({}, { numSwipes: 0 });
      } catch (err) {
        console.log("error resetNumSwipesDaily ", err);
      }
    },
    null,
    true,
    "America/Chicago"
  );
}
Example #8
Source File: cron.ts    From msclub-backend with GNU General Public License v3.0 6 votes vote down vote up
cronInit = () => {
	const crons = [];

	crons.push(
		new CronJob({
			cronTime: "*/20 * * * * *",
			onTick: async () => {
				await sendEmailWithTemplate();
			},
			timeZone: "Asia/Colombo",
		})
	);

	for (const cron of crons) {
		logger.info("? Starting MS Cron Processes");
		cron.start();
	}
}
Example #9
Source File: scheduler-registry.ts    From malagu with MIT License 6 votes vote down vote up
add(name: string, options: CronJobOptions): CronJob {
        let job = this.cronJobs.get(name);
        if (job) {
            throw new DuplicateSchedulerError(name);
        }
        job = this.cronJobFactory.create(options);
        this.cronJobs.set(name, job);
        return job;
    }
Example #10
Source File: global.ts    From corona-discord-webhook with MIT License 5 votes vote down vote up
job = new CronJob("0 18 * * *",
  async () => {
    const webhooks = config.webhook.Global;
    webhooks.forEach(async (item: any) => {
      const webhook = new WebhookClient(item.webhookID, item.webhookToken);
      const global = await get("https://covid19.mathdro.id/api");
      const countries = await get("https://covid19.mathdro.id/api/confirmed");

      const listCountry = countries.body
        .sort((a: any, b: any) => a.confirmed < b.confirmed)
        .slice(0, 10)
        .map(
          (item: any, i: any) =>
            `${i + 1}. ${item.countryRegion}: ${item.confirmed} Confirmed | ${
              item.recovered
            } Sembuh | ${item.deaths} Meninggal`
        )
        .join("\n");

      const embed = new MessageEmbed()
        .setAuthor(
          "COVID-19 in Global Daily Webhook",
          "https://cdn.glitch.com/c8c4439d-fc47-4f12-a21c-755bac53a055%2Frsz_200212152442-tak-i.png?v=1585125357606"
        )
        .setColor("RED")
        .setDescription(
          "Statistik 10 Negara paling rawan \n```" + listCountry + "```"
        )
        .addField(
          "Total " + global.body.confirmed.value + " kasus",
          `**Positif:** ${global.body.confirmed.value -
            global.body.recovered.value} | **Sembuh:** ${
            global.body.recovered.value
          } | **Meninggal:** ${global.body.deaths.value}`
        )
        .setFooter("Menggunakan data dari John Hopkins University CSSE")
        .setTimestamp();

      webhook.send(embed);

      console.log(
        `Message Delivery Success to ${item.name} !`,
        moment(Date.now()).format("LLLL")
      );
    });
  },
  null,
  true,
  "Asia/Jakarta"
)
Example #11
Source File: scheduler-registry.ts    From malagu with MIT License 5 votes vote down vote up
protected readonly cronJobs = new Map<string, CronJob>();
Example #12
Source File: scheduler-registry.ts    From malagu with MIT License 5 votes vote down vote up
getAll(): Map<string, CronJob> {
        return this.cronJobs;
    }
Example #13
Source File: scheduler-registry.ts    From malagu with MIT License 5 votes vote down vote up
get(name: string): CronJob {
        const job = this.cronJobs.get(name);
        if (!job) {
            throw new NoSchedulerFoundError(name);
        }
        return job;
    }
Example #14
Source File: cron-job-factory.ts    From malagu with MIT License 5 votes vote down vote up
create(options: CronJobOptions): CronJob {
        return new CronJob({...this.defaultCronJobOptions, ...options });
    }
Example #15
Source File: cron-job.ts    From malagu with MIT License 5 votes vote down vote up
export class FaaSCronJob extends CronJob {

    protected tickDisposable?: Disposable;

    constructor(protected readonly clock: Clock, options: CronJobOptions) {
        super(options);
    }

    protected async fireOnTickAsync() {
        const callbacks = (this as any)._callbacks;
        const context = (this as any).context;
        const onComplete = (this as any).onComplete;
        await Promise.all(callbacks.map((callback: any) => callback.call(context, onComplete)));
    };

    start() {
        if (this.running) {
            return;
        }

        this.tickDisposable = this.clock.onTick(async () => {

            const cronTime: CronTime = (this as any).cronTime;
            const timeout = cronTime.getTimeout();
            if (timeout <= 60 * 1000) {
                await this.fireOnTickAsync();
            }

        });
    }

    stop() {
        this.tickDisposable?.dispose();
        this.running = false;
        const onComplete = (this as any).onComplete;
        if (typeof onComplete === 'function') {
            onComplete();
        }
    }

}
Example #16
Source File: cron-job-factory.ts    From malagu with MIT License 5 votes vote down vote up
create(options: CronJobOptions): CronJob {
        if (this.mode.includes('remote')) {
            return new FaaSCronJob(this.clock, {...this.defaultCronJobOptions, ...options });
        } else {
            return super.create(options);
        }
    }
Example #17
Source File: indonesia.ts    From corona-discord-webhook with MIT License 5 votes vote down vote up
job = new CronJob("0 18 * * *", async () => {
  
  const webhooks = config.webhook.ID;
  
  webhooks.forEach(async (item: any) => {
  
  const webhook = new WebhookClient(item.webhookID, item.webhookToken);
  
  const indonesia = await get("https://indonesia-covid-19-api.now.sh/api");
  const provinsi = await get("https://indonesia-covid-19-api.now.sh/api/provinsi");
  
  const listProvinsi = provinsi.body.data
  .sort((a: any, b: any) => a.kasusPosi < b.kasusPosi)
  .slice(0, 10)
  .map((item: any, i: any) => `${i + 1}. ${item.provinsi}: ${item.kasusPosi} Positif | ${item.kasusSemb} Sembuh | ${item.kasusMeni} Meninggal`)
  .join("\n");
  
  const embed = new MessageEmbed()
      .setAuthor(
        "COVID-19 in Indonesia Daily Webhook",
        "https://cdn.glitch.com/c8c4439d-fc47-4f12-a21c-755bac53a055%2Frsz_200212152442-tak-i.png?v=1585125357606"
      )
      .setColor("RED")
      .setDescription("Statistik 10 Provinsi paling rawan \n```" + listProvinsi + "```")
      .addField(
        "Total " + indonesia.body.jumlahKasus + " kasus",
        `**Positif:** ${indonesia.body.perawatan} | **Sembuh:** ${indonesia.body.sembuh} | **Meninggal:** ${indonesia.body.meninggal}`
      )
      .addField(
        "More Info:",
        "[Kunjungi Website Resmi COVID-19 Indonesia](https://covid19.go.id/)"
      )
      .setFooter(
        "Menggunakan data dari https://github.com/mathdroid/indonesia-covid-19-api"
      )
      .setTimestamp();
  
  webhook.send(embed);
  
  console.log(`Message Delivery Success to ${item.name} !`, moment(Date.now()).format("LLLL"));
  })
}, null, true, "Asia/Jakarta")
Example #18
Source File: index.ts    From sync-party with GNU General Public License v3.0 4 votes vote down vote up
runApp = async () => {
    environment.setup(pathConfig, requiredEnvVars, validEnvValues);

    const authRateLimiter = rateLimiting.createRateLimiter(15);
    const catchallRateLimiter = rateLimiting.createRateLimiter(15);

    if (!fs.existsSync(path.resolve('data/uploads'))) {
        fs.mkdirSync(path.resolve('data/uploads'));
    }

    if (process.env.SERVER_PORT && process.env.WEBSOCKETS_PORT) {
        const webRtcServerKey = uuid();

        // Init app
        const app = express();

        // LOGGING
        const logger = loggers.createGeneralLogger(pathConfig);

        // DATABASE

        const sequelize = await database.create(dbConfig as TSFSDbConfig);

        const models = createModels(sequelize);

        try {
            await sequelize.sync({ alter: true });
        } catch (error) {
            logger.log('error', error);
        }

        // HTTP(S) SERVER

        const server = httpServer.create(app, sslDevKey, sslDevCert);

        // DEFAULT VALUES

        const persistentValues = fs.existsSync(
            path.resolve('data/persistence.json')
        )
            ? JSON.parse(
                  fs.readFileSync(
                      path.resolve('data/persistence.json'),
                      'utf-8'
                  )
              )
            : {
                  currentPlayWishes: {},
                  lastPositions: {}
              };

        const currentSyncStatus: {
            [partyId: string]: { [userId: string]: SyncStatus };
        } = {};
        const currentPlayWishes: {
            [partyId: string]: PlayWish;
        } = persistentValues.currentPlayWishes;
        const lastPositions: {
            [partyId: string]: { [itemId: string]: number };
        } = persistentValues.lastPositions;

        new CronJob(
            '*/15 * * * *',
            () => {
                fs.writeFileSync(
                    path.resolve('data/persistence.json'),
                    JSON.stringify({
                        currentPlayWishes,
                        lastPositions
                    })
                );
            },
            null,
            false
        ).start();

        // MIDDLEWARE

        headers.setup(app, {
            contentSecurityPolicy: {
                directives: {
                    defaultSrc:
                        contentSecurityPolicy.dangerouslyDisableDefaultSrc,
                    baseUri: ["'self'"],
                    fontSrc: ["'self'"],
                    objectSrc: ["'none'"],
                    scriptSrc:
                        "'self' 'unsafe-inline' www.youtube.com s.ytimg.com player.vimeo.com w.soundcloud.com",
                    scriptSrcAttr: ["'none'"],
                    styleSrc: "'self' https: 'unsafe-inline'"
                }
            }
        });

        performance.useCompression(app);

        // HTTP HEADERS

        // TODO: Consider cors package

        app.use((req, res, next) => {
            res.header('Cross-Origin-Resource-Policy', 'cross-origin');
            res.header('Cross-Origin-Embedder-Policy', 'unsafe-none');
            res.header('Access-Control-Allow-Credentials', 'true');
            res.header(
                'Access-Control-Allow-Headers',
                'X-Requested-With, Authorization, Content-Type, Accept, X-CSRF-Token'
            );
            res.header(
                'Access-Control-Allow-Methods',
                'POST, GET, DELETE, OPTIONS, PUT'
            );

            next();
        });

        // Static files middleware
        app.use(express.static(path.resolve('build/public')));

        // FIXME is this still applied with tsfs?
        // app.use(cookieParser(process.env.SESSION_SECRET));

        requestParsers.setup(app);

        // Session & Auth

        const { sessionMiddleware } = session.setup(
            app,
            sequelize,
            28 * 24 * 60 * 60 * 1000
        );

        const { passport } = authentication.setup(app, models.User);

        // TBI
        // app.use(
        //     csurf({
        //         cookie: { key: '_csrf', signed: false }
        //     })
        // );

        // CSRF Error Handler
        // app.use((err, req, res, next) => {
        //     if (err.code !== 'EBADCSRFTOKEN') return next(err);
        //     logger.log(
        //         'info',
        //         `Invalid CSRF token. User ID: ${
        //             req.user ? req.user.id : '(no session)'
        //         }`
        //     );
        //     return res.status(403).json({
        //         success: false,
        //         msg: 'csrfToken'
        //     });
        // });

        // WEBSOCKETS SERVER

        const socketServer =
            process.env.NODE_ENV === 'development'
                ? https.createServer({
                      key: sslDevKey,
                      cert: sslDevCert
                  })
                : http.createServer();

        const io = new SocketIoServer(socketServer, {
            transports: ['websocket'],
            cors:
                process.env.NODE_ENV === 'development'
                    ? {
                          origin: 'https://localhost:3000',
                          methods: ['GET']
                      }
                    : undefined
        });

        authenticateSocketRequest(io, sessionMiddleware, passport);

        // Socket listeners
        io.on('connection', (socket: Socket) => {
            // @ts-ignore Fixme user on request
            const socketUserId = socket.request.user.id;

            logger.log(
                'info',
                `Web Sockets: New connection, userId: ${socketUserId}`
            );

            const joinParty = async (data: {
                partyId: string;
                timestamp: number;
            }) => {
                const members: Set<string> = await io
                    .in(data.partyId)
                    .allSockets();

                if (!members.has(socketUserId)) {
                    try {
                        const party = await models.Party.findOne({
                            where: {
                                id: data.partyId
                            }
                        });

                        if (!party || !party.members.includes(socketUserId)) {
                            return Promise.reject(
                                new Error('User not member in party')
                            );
                        }
                    } catch (error) {
                        logger.log('error', error);
                    }

                    socket.join(data.partyId);

                    socket.emit(
                        'serverTimeOffset',
                        Date.now() - data.timestamp
                    );

                    logger.log(
                        'info',
                        `Web Sockets: User ${socketUserId} joined party ${data.partyId}`
                    );

                    if (currentPlayWishes[data.partyId]) {
                        socket.emit(
                            'playOrder',
                            currentPlayWishes[data.partyId]
                        );
                    }

                    return Promise.resolve();
                } else {
                    return Promise.reject(
                        new Error('User already joined the party')
                    );
                }
            };

            socket.on('joinParty', async (data: JoinPartyMessage) => {
                await joinParty(data);
            });

            socket.on('leaveParty', (data: LeavePartyMessage) => {
                socket.leave(data.partyId);

                logger.log(
                    'info',
                    `Web Sockets: User ${socketUserId} left party ${data.partyId}`
                );
            });

            socket.on('playWish', (playWish: PlayWish) => {
                const playWishWithNormalizedTimestamp = {
                    ...playWish,
                    timestamp:
                        playWish.timestamp + (Date.now() - playWish.timestamp)
                };

                // Save position of previous item, if delivered
                if (
                    playWish.lastPosition &&
                    playWish.lastPosition.position > 0
                ) {
                    if (!lastPositions[playWish.partyId]) {
                        lastPositions[playWish.partyId] = {};
                    }

                    lastPositions[playWish.partyId][
                        playWish.lastPosition.itemId
                    ] = playWish.lastPosition.position;
                }

                // Attach last position of the requested item
                if (
                    playWishWithNormalizedTimestamp.requestLastPosition &&
                    lastPositions[playWish.partyId] &&
                    lastPositions[playWish.partyId][
                        playWishWithNormalizedTimestamp.mediaItemId
                    ]
                ) {
                    playWishWithNormalizedTimestamp.lastPosition = {
                        itemId: playWishWithNormalizedTimestamp.mediaItemId,
                        position:
                            lastPositions[
                                playWishWithNormalizedTimestamp.partyId
                            ][playWishWithNormalizedTimestamp.mediaItemId]
                    };
                } else {
                    if (playWishWithNormalizedTimestamp.lastPosition) {
                        delete playWishWithNormalizedTimestamp.lastPosition;
                    }
                }

                currentPlayWishes[playWish.partyId] =
                    playWishWithNormalizedTimestamp;
                // Only emitted to party members
                io.to(playWish.partyId).emit(
                    'playOrder',
                    playWishWithNormalizedTimestamp
                );
            });

            socket.on('partyUpdate', (partyUpdateData: PartyUpdateMessage) => {
                // Update emitted to all connected users, in order to make sure dashboard is updated etc.
                io.emit('partyUpdate', partyUpdateData);
            });

            socket.on('mediaItemUpdate', (empty: MediaItemUpdateMessage) => {
                // Update emitted to all connected users, in order to make sure dashboard is updated etc.
                io.emit('mediaItemUpdate', empty);
            });

            socket.on(
                'syncStatus',
                (userSyncStatus: SyncStatusOutgoingMessage) => {
                    currentSyncStatus[userSyncStatus.partyId] =
                        currentSyncStatus[userSyncStatus.partyId] || {};
                    currentSyncStatus[userSyncStatus.partyId][
                        userSyncStatus.userId
                    ] = {
                        isPlaying: userSyncStatus.isPlaying,
                        timestamp: userSyncStatus.timestamp,
                        position: userSyncStatus.position,
                        serverTimeOffset: Date.now() - userSyncStatus.timestamp,
                        webRtc: userSyncStatus.webRtc
                    };

                    // Only emitted to party members
                    io.to(userSyncStatus.partyId).emit(
                        'syncStatus',
                        currentSyncStatus[userSyncStatus.partyId]
                    );
                }
            );

            socket.on('chatMessage', (chatMessage: ChatMessage) => {
                io.to(chatMessage.partyId).emit('chatMessage', chatMessage);
            });

            // WebRTC
            socket.on('joinWebRtc', (data: WebRtcJoinLeaveMessage) => {
                io.to(data.partyId).emit('joinWebRtc', data.webRtcId);
            });

            socket.on('leaveWebRtc', (data: WebRtcJoinLeaveMessage) => {
                io.to(data.partyId).emit('leaveWebRtc', {
                    webRtcId: data.webRtcId
                });
            });

            // Disconnect
            socket.on('disconnect', () => {
                logger.log(
                    'info',
                    `Web Sockets: User disconnected: ${socketUserId}`
                );
            });
        });

        // WebRTC

        const peerServer = ExpressPeerServer(server, {
            // debug: true,
            key: webRtcServerKey
        });

        app.use('/peerjs', authentication.mustBeAuthenticated, peerServer);

        peerServer.on('connection', async (client) => {
            const requestWebRtcId = client.getId();
            const allParties = await models.Party.findAll();
            let isInActiveParty = false;
            let userId = '';

            for (const party of allParties) {
                const partyWebRtcIds = party.settings.webRtcIds;

                if (partyWebRtcIds) {
                    for (const partyUserId of Object.keys(partyWebRtcIds)) {
                        const partyUserWebRtcId = partyWebRtcIds[partyUserId];

                        if (
                            partyUserWebRtcId === requestWebRtcId ||
                            party.status === 'active'
                        ) {
                            isInActiveParty = true;
                            userId = partyUserId;
                            break;
                        }
                    }
                }

                if (isInActiveParty) {
                    break;
                }
            }

            const user = await models.User.findOne({
                where: { id: userId }
            });

            if (!isInActiveParty || !user) {
                client.getSocket()?.close();
                logger.log(
                    'error',
                    `PeerJS: Client denied: ${requestWebRtcId}`
                );

                return;
            }

            logger.log(
                'info',
                `PeerJS: client connected: ${requestWebRtcId} (userId: ${user.id}, username: ${user.username})`
            );
        });

        peerServer.on('disconnect', (client: any) => {
            logger.log('info', `PeerJS: client disconnected: ${client.id}`);
        });

        // API Endpoints

        // Auth & login

        app.post('/api/auth', authRateLimiter, async (req, res) => {
            await authController.auth(req, res, logger);
        });

        app.post(
            '/api/login',
            authRateLimiter,
            passport.authenticate('local'),
            (req, res) => {
                authController.login(req, res);
            }
        );

        app.post(
            '/api/logout',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await authController.logout(req, res, logger);
            }
        );

        // WebRTC Key
        app.post(
            '/api/webRtcServerKey',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                const partyId = req.body.partyId;
                const userId = req.body.userId;
                const webRtcId = req.body.webRtcId;
                const party = await models.Party.findOne({
                    where: { id: partyId }
                });
                const user = await models.User.findOne({
                    where: { id: userId }
                });

                if (
                    !party ||
                    party.settings.webRtcIds[userId] !== webRtcId ||
                    !party.members.includes(userId) ||
                    !user
                ) {
                    return res.status(401);
                }

                return res.json({ webRtcServerKey });
            }
        );

        // MediaItems

        app.get(
            '/api/allMediaItems',
            authentication.mustBeAuthenticated,
            authentication.mustBeAdmin,
            async (req, res) => {
                await mediaItemController.getAllMediaItems(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        app.post(
            '/api/mediaItem',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await mediaItemController.createMediaItem(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        app.put(
            '/api/mediaItem/:id',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await mediaItemController.editMediaItem(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        app.delete(
            '/api/mediaItem/:id',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await mediaItemController.deleteMediaItem(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        // UserItems

        app.get(
            '/api/userItems',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await userItemController.getUserItems(req, res, models, logger);
            }
        );

        // Files

        app.get(
            '/api/file/:id',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await fileController.getFile(req, res, models);
            }
        );

        app.post(
            '/api/file',
            authentication.mustBeAuthenticated,
            (req, res) => {
                fileController.upload(req, res, models, logger);
            }
        );

        // Users

        app.get(
            '/api/allUsers',
            authentication.mustBeAuthenticated,
            authentication.mustBeAdmin,
            async (req, res) => {
                await userController.getAllUsers(req, res, models);
            }
        );

        // Parties

        app.post(
            '/api/party',
            authentication.mustBeAuthenticated,
            authentication.mustBeAdmin,
            async (req, res) => {
                await partyController.createParty(req, res, models, logger);
            }
        );

        app.put(
            '/api/party',
            authentication.mustBeAuthenticated,
            authentication.mustBeAdmin,
            async (req, res) => {
                await partyController.editParty(req, res, models, logger);
            }
        );

        // User Parties

        app.get(
            '/api/userParties',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await userPartyController.getUserParties(req, res, models);
            }
        );

        // Party items

        app.delete(
            '/api/partyItems',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await partyItemController.removeItemFromParty(req, res, models);
            }
        );

        app.post(
            '/api/partyItems',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await partyItemController.addItemToParty(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        app.put(
            '/api/partyItems',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await partyItemController.updatePartyItems(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        // Party metadata

        app.put(
            '/api/partyMetadata',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await partyMetadataController.updatePartyMetadata(
                    req,
                    res,
                    models,
                    logger
                );
            }
        );

        // Data from external websites

        app.post(
            '/api/linkMetadata',
            authentication.mustBeAuthenticated,
            async (req, res) => {
                await externalDataController.getLinkMetadata(req, res, logger);
            }
        );

        // Route everything not caught by above routes to index.html
        app.get('*', catchallRateLimiter, (req, res) => {
            res.sendFile(path.resolve('build/public/index.html'));
        });

        // Start Websockets server
        socketServer.listen(parseInt(process.env.WEBSOCKETS_PORT, 10), () => {
            logger.log(
                'info',
                `Websockets server listening on port ${process.env.WEBSOCKETS_PORT}`
            );
        });

        // Start server
        server.listen(process.env.SERVER_PORT, () => {
            logger.log(
                'info',
                `App listening on port ${process.env.SERVER_PORT}`
            );
        });
    } else {
        throw new Error('Env variables are missing.');
    }
}