Uploading minimal boilerplate

This commit is contained in:
Unknown committed 2019-02-13 21:30:15 +01:00
1 parent 8516cac965
commit 5652cb9b6d
42 files changed
+8144 -1

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
import 'dotenv/config';
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import schema from './schema';
import wrongPreshared from './errors/notAllowed.json';
const app = express();
app.post('/graphql', (req, res, next) => {
if (req.headers.preshared === process.env.PRESHARED_GATEWAY_KEY) {
next();
} else {
res.send(wrongPreshared);
}
});
// Starting the graphql server
const server = new ApolloServer({
schema,
playground: {
settings: {
'editor.theme': 'dark',
'editor.cursorShape': 'line',
},
},
context: ({ req }) => ({
userId: req.headers.userid,
authorization: req.headers.authorization,
}),
formatError: error => ({
code: error.extensions.exception.code,
message: error.message,
path: error.path,
}),
introspection: true,
});
server.applyMiddleware({
app,
cors: true,
});
export default app;
+11
View File
@@ -0,0 +1,11 @@
import 'dotenv/config';
import mongoose from 'mongoose';
mongoose.connect(`mongodb://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@${process.env.DB_DOMAIN}`, { useNewUrlParser: true });
mongoose.set('useCreateIndex', true);
mongoose.set('useFindAndModify', false);
mongoose.Promise = global.Promise;
const db = mongoose.connection;
export default db;
+19
View File
@@ -0,0 +1,19 @@
export const UNPUBLISHED = 'UNPUBLISHED';
export const PUBLISHED = 'PUBLISHED';
export const CANCELLED = 'CANCELLED';
export const RUNNING = 'RUNNING';
export const INTERRUPTED = 'INTERRUPTED';
export const FINISHED = 'FINISHED';
export const ARCHIVED = 'ARCHIVED';
export const EventStateEnum = [
UNPUBLISHED,
PUBLISHED,
CANCELLED,
RUNNING,
INTERRUPTED,
FINISHED,
ARCHIVED,
];
export default EventStateEnum;
+45
View File
@@ -0,0 +1,45 @@
import * as Sentry from '@sentry/node';
class ClientError extends Error {
constructor(args) {
super(args);
Sentry.configureScope((scope) => {
scope.setLevel('debug');
});
Sentry.captureException(this);
}
}
class ServerError extends Error {
constructor(args) {
super(args);
Sentry.configureScope((scope) => {
scope.setLevel('error');
});
Sentry.captureException(this);
}
}
export class AuthentificationError extends ClientError {
code = 401
message = 'Autentification not found, you have to be authentificated to perform this action'
}
export class DatabaseError extends ClientError {
code = 404
message = `Ressource not found : ${this.message}`
}
export class WrongArgumentsError extends ClientError {
code = 400
message = `Wrong arguments : ${this.message}`
}
export class ServiceUnavailableError extends ServerError {
code = 503
message = `At least one service is unresponding ${this.message}`
}
+8
View File
@@ -0,0 +1,8 @@
{
"errors": [
{
"code": 401,
"message": "Wait, you're not supposed to be here, go through the gate as everyone else"
}
]
}
+14
View File
@@ -0,0 +1,14 @@
/* eslint-disable no-console */
import db from './db';
import app from './app';
db.on('error', (err) => {
console.log(err);
});
db.once('open', () => {
console.log('Connected to the DB.');
});
app.listen(process.env.PORT, () => {
console.log(`Listening on port ${process.env.PORT}`);
});
+60
View File
@@ -0,0 +1,60 @@
import mongoose, { Schema } from 'mongoose';
import Plotter from './plotter';
import Formula from './formula';
import {
UNPUBLISHED,
EventStateEnum,
} from '../enums/EventState';
const { ObjectId } = Schema.Types;
const eventSchema = new Schema({
state: {
type: String,
enum: EventStateEnum,
default: UNPUBLISHED,
},
name: {
type: String,
required: true,
},
hostId: {
type: String,
required: true,
},
formulaId: {
type: ObjectId,
ref: Formula.modelName,
},
plotterId: {
type: ObjectId,
ref: Plotter.modelName,
},
prizes: [{
rank: {
type: String,
required: true,
},
subPrize: [{
condition: String,
}],
}],
});
eventSchema.pre('find', function populate() {
this.populate('formulaId').populate('plotterId');
});
eventSchema.post('save', (doc, next) => {
doc.populate('formulaId').populate('plotterId').execPopulate().then(() => {
next();
});
});
eventSchema.post('findOneAndUpdate', (doc, next) => {
doc.populate('formulaId').populate('plotterId').execPopulate().then(() => {
next();
});
});
const Event = mongoose.model('Event', eventSchema);
export default Event;
+12
View File
@@ -0,0 +1,12 @@
import mongoose, { Schema } from 'mongoose';
const formulaSchema = new Schema({
name: {
type: String,
required: true,
},
});
const Formula = mongoose.model('Formula', formulaSchema);
export default Formula;
+9
View File
@@ -0,0 +1,9 @@
import Plotter from './plotter';
import Event from './event';
import Formula from './formula';
export {
Event,
Plotter,
Formula,
};
+12
View File
@@ -0,0 +1,12 @@
import mongoose, { Schema } from 'mongoose';
const plotterSchema = new Schema({
name: {
type: String,
required: true,
},
});
const Plotter = mongoose.model('Plotter', plotterSchema);
export default Plotter;
+13
View File
@@ -0,0 +1,13 @@
import {
GraphQLSchema,
} from 'graphql';
import Mutation from './mutations';
import RootQuery from './queries';
const Schema = new GraphQLSchema({
query: RootQuery,
mutation: Mutation,
});
export default Schema;
+39
View File
@@ -0,0 +1,39 @@
import {
GraphQLNonNull,
GraphQLID,
} from 'graphql';
import { AuthentificationError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import EventStateEnum from '../types/enum/EventState';
const args = {
eventId: { type: new GraphQLNonNull(GraphQLID) },
state: { type: EventStateEnum },
};
const resolve = (parent, { eventId: _id, state }, { userId: hostId }) => {
if (!hostId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
Event.findOneAndUpdate({ _id, hostId }, { state }, { new: true }, (err, modifiedEvent) => {
if (err) {
rej(err);
return;
}
res(modifiedEvent);
});
});
};
const mutation = {
changeEventState: {
type: EventType,
args,
resolve,
},
};
export default mutation;
+37
View File
@@ -0,0 +1,37 @@
import { AuthentificationError } from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
import { EventInputType } from '../types/input';
export const args = {
event: { type: EventInputType },
};
const resolve = (parent, { event }, { userId: hostId }) => {
if (!hostId) {
throw new AuthentificationError();
}
event.hostId = hostId;
const newEvent = new Event(event);
return new Promise((res, rej) => {
newEvent.save((err) => {
if (err) {
rej(err);
return;
}
res(newEvent);
});
});
};
const mutation = {
createEvent: {
type: EventType,
args,
resolve,
},
};
export default mutation;
+81
View File
@@ -0,0 +1,81 @@
import {
GraphQLNonNull,
GraphQLID,
} from 'graphql';
import axios from 'axios';
import {
AuthentificationError,
WrongArgumentsError,
ServiceUnavailableError,
} from '../../errors';
import { EventType } from '../types';
import { Event } from '../../models';
const args = {
eventId: { type: new GraphQLNonNull(GraphQLID) },
};
const resolve = (parent,
{ eventId: _id, participant: { teamId, botId, releaseId } },
{ userId, authorization }) => {
if (!userId) {
throw new AuthentificationError();
}
return new Promise((res, rej) => {
axios({
url: process.env.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
{
teams_TeamsByRole{
id
}
}
`,
},
headers: { authorization },
}).then(
(result) => {
if (!result.data.data.teamsByRole.some(team => team.id === teamId)) {
rej(new WrongArgumentsError('You are not eligible to edit this team'));
return;
}
Event.findOne({ _id }).exec((err, event) => {
if (err) {
rej(err);
return;
}
const participantIndex = event.participant
.findIndex(participant => participant.teamId === teamId);
event.participants[participantIndex].botId = botId
|| event.participants[participantIndex].botId;
event.participants[participantIndex].releaseId = releaseId
|| event.participants[participantIndex].releaseId;
event.save((error) => {
if (error) {
rej(error);
return;
}
res(event);
});
});
},
(error) => {
rej(new ServiceUnavailableError(error));
},
);
});
};
const mutation = {
editParticipant: {
type: EventType,
args,
resolve,
},
};
export default mutation;
+16
View File
@@ -0,0 +1,16 @@
import {
GraphQLObjectType,
} from 'graphql';
import CreateEventMutation from './CreateEvent';
import ChangeEventStateMutation from './ChangeEventState';
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: Object.assign(
CreateEventMutation,
ChangeEventStateMutation,
),
});
export default Mutation;
+37
View File
@@ -0,0 +1,37 @@
import {
GraphQLInt,
GraphQLList,
} from 'graphql';
import { EventType } from '../types';
import { Event } from '../../models';
import { UNPUBLISHED, ARCHIVED } from '../../enums/EventState';
const args = {
minDate: { type: GraphQLInt },
maxDate: { type: GraphQLInt },
};
const resolve = (parent, { minDate, maxDate }) => Event.find(
Object.assign(
{ state: { $nin: [UNPUBLISHED, ARCHIVED] } },
minDate || maxDate
? {
startDatetime:
Object.assign(
minDate ? { $gte: minDate } : {},
maxDate ? { $lte: maxDate } : {},
),
}
: {},
),
);
const query = {
events: {
type: new GraphQLList(EventType),
args,
resolve,
},
};
export default query;
+39
View File
@@ -0,0 +1,39 @@
import {
GraphQLInt,
GraphQLList,
GraphQLString,
} from 'graphql';
import { EventType } from '../types';
import { Event } from '../../models';
import { UNPUBLISHED, ARCHIVED } from '../../enums/EventState';
const args = {
hostId: { type: GraphQLString },
minDate: { type: GraphQLInt },
maxDate: { type: GraphQLInt },
};
const resolve = (parent, { hostId, minDate, maxDate }, context) => Event.find(
Object.assign(
hostId ? { hostId, state: { $nin: [UNPUBLISHED, ARCHIVED] } } : { hostId: context.userId },
minDate || maxDate
? {
startDatetime:
Object.assign(
minDate ? { $gte: minDate } : {},
maxDate ? { $lte: maxDate } : {},
),
}
: {},
),
);
const query = {
eventsByHost: {
type: new GraphQLList(EventType),
args,
resolve,
},
};
export default query;
+16
View File
@@ -0,0 +1,16 @@
import {
GraphQLObjectType,
} from 'graphql';
import EventsQuery from './Events';
import EventsByHostQuery from './EventsByHost';
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: Object.assign(
EventsQuery,
EventsByHostQuery,
),
});
export default RootQuery;
+43
View File
@@ -0,0 +1,43 @@
import {
GraphQLObjectType,
GraphQLString,
GraphQLList,
GraphQLID,
} from 'graphql';
import {
FormulaType,
PlotterType,
PrizeType,
} from './index';
import EventStateEnumType from './enum/EventState';
const EventType = new GraphQLObjectType({
name: 'Event',
description: 'Everything you need to know about an event',
fields: () => ({
id: { type: GraphQLID },
state: { type: EventStateEnumType },
name: { type: GraphQLString },
hostId: { type: GraphQLString },
formula: {
type: FormulaType,
resolve(parent) {
return parent.formulaId;
},
},
plotter: {
type: PlotterType,
resolve(parent) {
return parent.plotterId;
},
},
prizes: {
type: new GraphQLList(PrizeType),
resolve(parent) {
return parent.prizes;
},
},
}),
});
export default EventType;
+15
View File
@@ -0,0 +1,15 @@
import {
GraphQLObjectType,
GraphQLString,
} from 'graphql';
const FormulaType = new GraphQLObjectType({
name: 'Formula',
description: 'For now it\'s simplay a named field',
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
}),
});
export default FormulaType;
+15
View File
@@ -0,0 +1,15 @@
import {
GraphQLObjectType,
GraphQLString,
} from 'graphql';
const PlotterType = new GraphQLObjectType({
name: 'Plotter',
description: 'Will soon change in order to use contained plotter objects',
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
}),
});
export default PlotterType;
+23
View File
@@ -0,0 +1,23 @@
import {
GraphQLObjectType,
GraphQLList,
GraphQLString,
GraphQLNonNull,
} from 'graphql';
import { SubPrizeType } from './index';
const PrizeType = new GraphQLObjectType({
name: 'Prize',
description: 'Prize, by default in algos',
fields: () => ({
rank: { type: new GraphQLNonNull(GraphQLString) },
subPrize: {
type: new GraphQLList(SubPrizeType),
resolve(parent) {
return parent.subPrize;
},
},
}),
});
export default PrizeType;
+14
View File
@@ -0,0 +1,14 @@
import {
GraphQLObjectType,
GraphQLString,
} from 'graphql';
const SubPrizeType = new GraphQLObjectType({
name: 'SubPrize',
description: 'Prize',
fields: () => ({
condition: { type: GraphQLString },
}),
});
export default SubPrizeType;
+19
View File
@@ -0,0 +1,19 @@
import {
GraphQLEnumType,
} from 'graphql';
import { EventStateEnum } from '../../../enums/EventState';
const values = {};
EventStateEnum.forEach((EventState) => {
values[EventState] = { value: EventState };
});
const EventStateEnumType = new GraphQLEnumType({
name: 'EventStateEnum',
values,
});
export {
EventStateEnumType as default,
};
+13
View File
@@ -0,0 +1,13 @@
import PlotterType from './Plotter';
import SubPrizeType from './SubPrize';
import PrizeType from './Prize';
import FormulaType from './Formula';
import EventType from './Event';
export {
PlotterType,
SubPrizeType,
PrizeType,
FormulaType,
EventType,
};
+19
View File
@@ -0,0 +1,19 @@
import {
GraphQLString,
GraphQLInputObjectType,
GraphQLList,
} from 'graphql';
import InputPrizeType from './Prize';
const Type = new GraphQLInputObjectType({
name: 'EventInput',
description: 'Payload for event input',
fields: () => ({
name: { type: GraphQLString },
formulaId: { type: GraphQLString },
plotterId: { type: GraphQLString },
prizes: { type: new GraphQLList(InputPrizeType) },
}),
});
export default Type;
+15
View File
@@ -0,0 +1,15 @@
import {
GraphQLNonNull,
GraphQLString,
GraphQLInputObjectType,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'FormulaInput',
description: 'Payload for formula input',
fields: () => ({
name: { type: new GraphQLNonNull(GraphQLString) },
}),
});
export default Type;
+15
View File
@@ -0,0 +1,15 @@
import {
GraphQLNonNull,
GraphQLString,
GraphQLInputObjectType,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'PlotterInput',
description: 'Payload for plotter input',
fields: () => ({
name: { type: new GraphQLNonNull(GraphQLString) },
}),
});
export default Type;
+21
View File
@@ -0,0 +1,21 @@
import {
GraphQLInputObjectType,
GraphQLList,
GraphQLInt,
GraphQLNonNull,
} from 'graphql';
import InputSubPrizeType from './SubPrize';
const Type = new GraphQLInputObjectType({
name: 'PrizeInput',
description: 'Payload for formula input',
fields: () => ({
rank: { type: new GraphQLNonNull(GraphQLInt) },
amount: { type: new GraphQLNonNull(GraphQLInt) },
subPrize: {
type: new GraphQLList(InputSubPrizeType),
},
}),
});
export default Type;
+14
View File
@@ -0,0 +1,14 @@
import {
GraphQLInputObjectType,
GraphQLString,
} from 'graphql';
const Type = new GraphQLInputObjectType({
name: 'SubPrizeInput',
description: 'Payload prize input',
fields: () => ({
condition: { type: GraphQLString },
}),
});
export default Type;
+13
View File
@@ -0,0 +1,13 @@
import PlotterInputType from './Plotter';
import PrizeInputType from './Prize';
import FormulaInputType from './Formula';
import EventInputType from './Event';
import SubPrizeInputType from './SubPrize';
export {
PlotterInputType,
PrizeInputType,
FormulaInputType,
EventInputType,
SubPrizeInputType,
};
View File
Whitespace-only changes.