Remove old controllers, add fulfillment mode, fix relations, add missing GraphQL queries and mutations
Added create mutations for the models
This commit is contained in:
parent
d076e0a013
commit
832cf07aa5
45 changed files with 546 additions and 1175 deletions
|
@ -15,6 +15,8 @@ import { UserResolver } from './graphql-resolvers/user.resolver';
|
|||
import { SzakdolgozatAuthChecker } from './szakdolgozat-auth-checker';
|
||||
import { CourseResolver } from './graphql-resolvers/course.resolver';
|
||||
import { SubjectResolver } from './graphql-resolvers/subject.resolver';
|
||||
import { FulfillmentModeResolver } from './graphql-resolvers/fulfillment-mode.resolver';
|
||||
import { RequirementResolver } from './graphql-resolvers/requirement.resolver';
|
||||
|
||||
export { ApplicationConfig };
|
||||
|
||||
|
@ -36,6 +38,8 @@ export class SzakdolgozatBackendApplication extends BootMixin(
|
|||
s.resolver(UserResolver);
|
||||
s.resolver(CourseResolver);
|
||||
s.resolver(SubjectResolver);
|
||||
s.resolver(FulfillmentModeResolver);
|
||||
s.resolver(RequirementResolver);
|
||||
});
|
||||
|
||||
// Authentication
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
import {
|
||||
Count,
|
||||
CountSchema,
|
||||
Filter,
|
||||
repository,
|
||||
Where,
|
||||
} from '@loopback/repository';
|
||||
import {
|
||||
del,
|
||||
get,
|
||||
getModelSchemaRef,
|
||||
getWhereSchemaFor,
|
||||
param,
|
||||
patch,
|
||||
post,
|
||||
requestBody,
|
||||
} from '@loopback/rest';
|
||||
import {
|
||||
Course,
|
||||
Requirement,
|
||||
} from '../models';
|
||||
import { CourseRepository } from '../repositories';
|
||||
|
||||
export class CourseRequirementController {
|
||||
constructor(
|
||||
@repository(CourseRepository) protected courseRepository: CourseRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@get('/courses/{id}/requirements', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Array of Course has many Requirement',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {type: 'array', items: getModelSchemaRef(Requirement)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('filter') filter?: Filter<Requirement>,
|
||||
): Promise<Requirement[]> {
|
||||
return this.courseRepository.requirements(id).find(filter);
|
||||
}
|
||||
|
||||
@post('/courses/{id}/requirements', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Course model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(Requirement)}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async create(
|
||||
@param.path.number('id') id: typeof Course.prototype.id,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Requirement, {
|
||||
title: 'NewRequirementInCourse',
|
||||
exclude: ['id'],
|
||||
optional: ['courseId']
|
||||
}),
|
||||
},
|
||||
},
|
||||
}) requirement: Omit<Requirement, 'id'>,
|
||||
): Promise<Requirement> {
|
||||
return this.courseRepository.requirements(id).create(requirement);
|
||||
}
|
||||
|
||||
@patch('/courses/{id}/requirements', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Course.Requirement PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async patch(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Requirement, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
requirement: Partial<Requirement>,
|
||||
@param.query.object('where', getWhereSchemaFor(Requirement)) where?: Where<Requirement>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.requirements(id).patch(requirement, where);
|
||||
}
|
||||
|
||||
@del('/courses/{id}/requirements', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Course.Requirement DELETE success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async delete(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('where', getWhereSchemaFor(Requirement)) where?: Where<Requirement>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.requirements(id).delete(where);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import {
|
||||
repository,
|
||||
} from '@loopback/repository';
|
||||
import {
|
||||
param,
|
||||
get,
|
||||
getModelSchemaRef,
|
||||
} from '@loopback/rest';
|
||||
import {
|
||||
Course,
|
||||
Subject,
|
||||
} from '../models';
|
||||
import { CourseRepository } from '../repositories';
|
||||
|
||||
export class CourseSubjectController {
|
||||
constructor(
|
||||
@repository(CourseRepository)
|
||||
public courseRepository: CourseRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@get('/courses/{id}/subject', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Subject belonging to Course',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {type: 'array', items: getModelSchemaRef(Subject)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async getSubject(
|
||||
@param.path.number('id') id: typeof Course.prototype.id,
|
||||
): Promise<Subject> {
|
||||
return this.courseRepository.subject(id);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
import {
|
||||
Count,
|
||||
CountSchema,
|
||||
Filter,
|
||||
repository,
|
||||
Where,
|
||||
} from '@loopback/repository';
|
||||
import {
|
||||
del,
|
||||
get,
|
||||
getModelSchemaRef,
|
||||
getWhereSchemaFor,
|
||||
param,
|
||||
patch,
|
||||
post,
|
||||
requestBody,
|
||||
} from '@loopback/rest';
|
||||
import {
|
||||
Course,
|
||||
User,
|
||||
} from '../models';
|
||||
import { CourseRepository } from '../repositories';
|
||||
|
||||
export class CourseUserController {
|
||||
constructor(
|
||||
@repository(CourseRepository) protected courseRepository: CourseRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@get('/courses/{id}/users', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Array of Course has many User through CourseUser',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {type: 'array', items: getModelSchemaRef(User)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('filter') filter?: Filter<User>,
|
||||
): Promise<User[]> {
|
||||
return this.courseRepository.users(id).find(filter);
|
||||
}
|
||||
|
||||
@post('/courses/{id}/users', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'create a User model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(User)}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async create(
|
||||
@param.path.number('id') id: typeof Course.prototype.id,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {
|
||||
title: 'NewUserInCourse',
|
||||
exclude: ['id'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
}) user: Omit<User, 'id'>,
|
||||
): Promise<User> {
|
||||
return this.courseRepository.users(id).create(user);
|
||||
}
|
||||
|
||||
@patch('/courses/{id}/users', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Course.User PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async patch(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
user: Partial<User>,
|
||||
@param.query.object('where', getWhereSchemaFor(User)) where?: Where<User>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.users(id).patch(user, where);
|
||||
}
|
||||
|
||||
@del('/courses/{id}/users', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Course.User DELETE success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async delete(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('where', getWhereSchemaFor(User)) where?: Where<User>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.users(id).delete(where);
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
import { Count, CountSchema, Filter, FilterExcludingWhere, repository, Where, } from '@loopback/repository';
|
||||
import { del, get, getModelSchemaRef, param, patch, post, put, requestBody, response, } from '@loopback/rest';
|
||||
import { Course } from '../models';
|
||||
import { CourseRepository } from '../repositories';
|
||||
|
||||
export class CourseController {
|
||||
constructor(
|
||||
@repository(CourseRepository)
|
||||
public courseRepository: CourseRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@post('/courses')
|
||||
@response(200, {
|
||||
description: 'Course model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(Course)}},
|
||||
})
|
||||
async create(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {
|
||||
title: 'NewCourse',
|
||||
exclude: ['id'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Omit<Course, 'id'>,
|
||||
): Promise<Course> {
|
||||
return this.courseRepository.create(course);
|
||||
}
|
||||
|
||||
@get('/courses/count')
|
||||
@response(200, {
|
||||
description: 'Course model count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async count(
|
||||
@param.where(Course) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.count(where);
|
||||
}
|
||||
|
||||
@get('/courses')
|
||||
@response(200, {
|
||||
description: 'Array of Course model instances',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: getModelSchemaRef(Course, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.filter(Course) filter?: Filter<Course>,
|
||||
): Promise<Course[]> {
|
||||
return this.courseRepository.find(filter);
|
||||
}
|
||||
|
||||
@patch('/courses')
|
||||
@response(200, {
|
||||
description: 'Course PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async updateAll(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Course,
|
||||
@param.where(Course) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.updateAll(course, where);
|
||||
}
|
||||
|
||||
@get('/courses/{id}')
|
||||
@response(200, {
|
||||
description: 'Course model instance',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
async findById(
|
||||
@param.path.number('id') id: number,
|
||||
@param.filter(Course, {exclude: 'where'}) filter?: FilterExcludingWhere<Course>
|
||||
): Promise<Course> {
|
||||
return this.courseRepository.findById(id, filter);
|
||||
}
|
||||
|
||||
@patch('/courses/{id}')
|
||||
@response(204, {
|
||||
description: 'Course PATCH success',
|
||||
})
|
||||
async updateById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Course,
|
||||
): Promise<void> {
|
||||
await this.courseRepository.updateById(id, course);
|
||||
}
|
||||
|
||||
@put('/courses/{id}')
|
||||
@response(204, {
|
||||
description: 'Course PUT success',
|
||||
})
|
||||
async replaceById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody() course: Course,
|
||||
): Promise<void> {
|
||||
await this.courseRepository.replaceById(id, course);
|
||||
}
|
||||
|
||||
@del('/courses/{id}')
|
||||
@response(204, {
|
||||
description: 'Course DELETE success',
|
||||
})
|
||||
async deleteById(@param.path.number('id') id: number): Promise<void> {
|
||||
await this.courseRepository.deleteById(id);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
export * from './ping.controller';
|
||||
export * from './user.controller';
|
||||
export * from './subject-course.controller';
|
||||
export * from './course-subject.controller';
|
||||
export * from './course-user.controller';
|
||||
export * from './user-course.controller';
|
||||
export * from './course-requirement.controller';
|
||||
export * from './course-requirement.controller';
|
||||
export * from './subject.controller';
|
||||
export * from './course.controller';
|
|
@ -1,55 +0,0 @@
|
|||
import {inject} from '@loopback/core';
|
||||
import {
|
||||
Request,
|
||||
RestBindings,
|
||||
get,
|
||||
response,
|
||||
ResponseObject,
|
||||
} from '@loopback/rest';
|
||||
|
||||
/**
|
||||
* OpenAPI response for ping()
|
||||
*/
|
||||
const PING_RESPONSE: ResponseObject = {
|
||||
description: 'Ping Response',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
title: 'PingResponse',
|
||||
properties: {
|
||||
greeting: {type: 'string'},
|
||||
date: {type: 'string'},
|
||||
url: {type: 'string'},
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': {type: 'string'},
|
||||
},
|
||||
additionalProperties: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* A simple controller to bounce back http requests
|
||||
*/
|
||||
export class PingController {
|
||||
constructor(@inject(RestBindings.Http.REQUEST) private req: Request) {}
|
||||
|
||||
// Map to `GET /ping`
|
||||
@get('/ping')
|
||||
@response(200, PING_RESPONSE)
|
||||
ping(): object {
|
||||
// Reply with a greeting, the current time, the url, and request headers
|
||||
return {
|
||||
greeting: 'Hello from LoopBack',
|
||||
date: new Date(),
|
||||
url: this.req.url,
|
||||
headers: Object.assign({}, this.req.headers),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
import { Count, CountSchema, Filter, repository, Where, } from '@loopback/repository';
|
||||
import { del, get, getModelSchemaRef, getWhereSchemaFor, param, patch, post, requestBody, response, } from '@loopback/rest';
|
||||
import { Course, Subject, } from '../models';
|
||||
import { SubjectRepository } from '../repositories';
|
||||
|
||||
export class SubjectCourseController {
|
||||
constructor(
|
||||
@repository(SubjectRepository) protected subjectRepository: SubjectRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@get('/subjects/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Array of Subject has many Course',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {type: 'array', items: getModelSchemaRef(Course)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('filter') filter?: Filter<Course>,
|
||||
): Promise<Course[]> {
|
||||
return this.subjectRepository.courses(id).find(filter);
|
||||
}
|
||||
|
||||
@get('/subjects/{id}/courses/count')
|
||||
@response(200, {
|
||||
description: 'Course model count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async count(
|
||||
@param.path.number('id') id: number,
|
||||
@param.where(Course) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.subjectRepository.courses(id).count(where);
|
||||
}
|
||||
|
||||
@post('/subjects/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Subject model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(Course)}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async create(
|
||||
@param.path.number('id') id: typeof Subject.prototype.id,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {
|
||||
title: 'NewCourseInSubject',
|
||||
exclude: ['id'],
|
||||
optional: ['subjectId']
|
||||
}),
|
||||
},
|
||||
},
|
||||
}) course: Omit<Course, 'id'>,
|
||||
): Promise<Course> {
|
||||
return this.subjectRepository.courses(id).create(course);
|
||||
}
|
||||
|
||||
@patch('/subjects/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Subject.Course PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async patch(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Partial<Course>,
|
||||
@param.query.object('where', getWhereSchemaFor(Course)) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.subjectRepository.courses(id).patch(course, where);
|
||||
}
|
||||
|
||||
@del('/subjects/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Subject.Course DELETE success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async delete(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('where', getWhereSchemaFor(Course)) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.subjectRepository.courses(id).delete(where);
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
import {
|
||||
Count,
|
||||
CountSchema,
|
||||
Filter,
|
||||
FilterExcludingWhere,
|
||||
repository,
|
||||
Where,
|
||||
} from '@loopback/repository';
|
||||
import {
|
||||
post,
|
||||
param,
|
||||
get,
|
||||
getModelSchemaRef,
|
||||
patch,
|
||||
put,
|
||||
del,
|
||||
requestBody,
|
||||
response,
|
||||
} from '@loopback/rest';
|
||||
import { Subject } from '../models';
|
||||
import { SubjectRepository } from '../repositories';
|
||||
|
||||
export class SubjectController {
|
||||
constructor(
|
||||
@repository(SubjectRepository)
|
||||
public subjectRepository: SubjectRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@post('/subjects')
|
||||
@response(200, {
|
||||
description: 'Subject model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(Subject)}},
|
||||
})
|
||||
async create(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Subject, {
|
||||
title: 'NewSubject',
|
||||
exclude: ['id'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
subject: Omit<Subject, 'id'>,
|
||||
): Promise<Subject> {
|
||||
return this.subjectRepository.create(subject);
|
||||
}
|
||||
|
||||
@get('/subjects/count')
|
||||
@response(200, {
|
||||
description: 'Subject model count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async count(
|
||||
@param.where(Subject) where?: Where<Subject>,
|
||||
): Promise<Count> {
|
||||
return this.subjectRepository.count(where);
|
||||
}
|
||||
|
||||
@get('/subjects')
|
||||
@response(200, {
|
||||
description: 'Array of Subject model instances',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: getModelSchemaRef(Subject, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.filter(Subject) filter?: Filter<Subject>,
|
||||
): Promise<Subject[]> {
|
||||
return this.subjectRepository.find(filter);
|
||||
}
|
||||
|
||||
@patch('/subjects')
|
||||
@response(200, {
|
||||
description: 'Subject PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async updateAll(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Subject, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
subject: Subject,
|
||||
@param.where(Subject) where?: Where<Subject>,
|
||||
): Promise<Count> {
|
||||
return this.subjectRepository.updateAll(subject, where);
|
||||
}
|
||||
|
||||
@get('/subjects/{id}')
|
||||
@response(200, {
|
||||
description: 'Subject model instance',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Subject, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
async findById(
|
||||
@param.path.number('id') id: number,
|
||||
@param.filter(Subject, {exclude: 'where'}) filter?: FilterExcludingWhere<Subject>
|
||||
): Promise<Subject> {
|
||||
return this.subjectRepository.findById(id, filter);
|
||||
}
|
||||
|
||||
@patch('/subjects/{id}')
|
||||
@response(204, {
|
||||
description: 'Subject PATCH success',
|
||||
})
|
||||
async updateById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Subject, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
subject: Subject,
|
||||
): Promise<void> {
|
||||
await this.subjectRepository.updateById(id, subject);
|
||||
}
|
||||
|
||||
@put('/subjects/{id}')
|
||||
@response(204, {
|
||||
description: 'Subject PUT success',
|
||||
})
|
||||
async replaceById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody() subject: Subject,
|
||||
): Promise<void> {
|
||||
await this.subjectRepository.replaceById(id, subject);
|
||||
}
|
||||
|
||||
@del('/subjects/{id}')
|
||||
@response(204, {
|
||||
description: 'Subject DELETE success',
|
||||
})
|
||||
async deleteById(@param.path.number('id') id: number): Promise<void> {
|
||||
await this.subjectRepository.deleteById(id);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
import {
|
||||
Count,
|
||||
CountSchema,
|
||||
Filter,
|
||||
repository,
|
||||
Where,
|
||||
} from '@loopback/repository';
|
||||
import {
|
||||
del,
|
||||
get,
|
||||
getModelSchemaRef,
|
||||
getWhereSchemaFor,
|
||||
param,
|
||||
patch,
|
||||
post,
|
||||
requestBody,
|
||||
} from '@loopback/rest';
|
||||
import {
|
||||
User,
|
||||
Course,
|
||||
} from '../models';
|
||||
import { UserRepository } from '../repositories';
|
||||
|
||||
export class UserCourseController {
|
||||
constructor(
|
||||
@repository(UserRepository) protected userRepository: UserRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@get('/users/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Array of User has many Course through CourseUser',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {type: 'array', items: getModelSchemaRef(Course)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('filter') filter?: Filter<Course>,
|
||||
): Promise<Course[]> {
|
||||
return this.userRepository.courses(id).find(filter);
|
||||
}
|
||||
|
||||
@post('/users/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'create a Course model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(Course)}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async create(
|
||||
@param.path.number('id') id: typeof User.prototype.id,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {
|
||||
title: 'NewCourseInUser',
|
||||
exclude: ['id'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
}) course: Omit<Course, 'id'>,
|
||||
): Promise<Course> {
|
||||
return this.userRepository.courses(id).create(course);
|
||||
}
|
||||
|
||||
@patch('/users/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'User.Course PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async patch(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Partial<Course>,
|
||||
@param.query.object('where', getWhereSchemaFor(Course)) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.userRepository.courses(id).patch(course, where);
|
||||
}
|
||||
|
||||
@del('/users/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'User.Course DELETE success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
},
|
||||
},
|
||||
})
|
||||
async delete(
|
||||
@param.path.number('id') id: number,
|
||||
@param.query.object('where', getWhereSchemaFor(Course)) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.userRepository.courses(id).delete(where);
|
||||
}
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
import { Count, CountSchema, Filter, FilterExcludingWhere, repository, Where, } from '@loopback/repository';
|
||||
import { del, get, getModelSchemaRef, HttpErrors, param, patch, post, Request, requestBody, response, RestBindings, } from '@loopback/rest';
|
||||
import { User } from '../models';
|
||||
import { UserRepository } from '../repositories';
|
||||
import {
|
||||
TokenServiceBindings,
|
||||
UserServiceBindings
|
||||
} from '@loopback/authentication-jwt';
|
||||
import { inject } from '@loopback/core';
|
||||
import { authenticate, TokenService } from '@loopback/authentication';
|
||||
import { SecurityBindings, UserProfile } from '@loopback/security';
|
||||
import { genSalt, hash } from 'bcryptjs';
|
||||
import { SzakdolgozatUserService } from '../services';
|
||||
|
||||
export class UserController {
|
||||
constructor(
|
||||
@inject(TokenServiceBindings.TOKEN_SERVICE)
|
||||
public jwtService: TokenService,
|
||||
@inject(UserServiceBindings.USER_SERVICE)
|
||||
public userService: SzakdolgozatUserService,
|
||||
@inject(SecurityBindings.USER, {optional: true})
|
||||
public user: UserProfile,
|
||||
@repository(UserRepository)
|
||||
public userRepository: UserRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@post('/users')
|
||||
@response(200, {
|
||||
description: 'User model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(User, {exclude: ['password']})}},
|
||||
})
|
||||
async register(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {
|
||||
title: 'Registration request',
|
||||
exclude: ['id', 'isAdmin']
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
request: Pick<User, 'email' | 'name' | 'password'>,
|
||||
): Promise<User> {
|
||||
const password = await hash(request.password, await genSalt());
|
||||
const user = {
|
||||
email: request.email,
|
||||
name: request.name,
|
||||
password: password,
|
||||
isAdmin: false
|
||||
} as User;
|
||||
return this.userRepository.create(user);
|
||||
}
|
||||
|
||||
@post('/users/login', {
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Token',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
token: {
|
||||
type: 'string',
|
||||
},
|
||||
user: getModelSchemaRef(User, {exclude: ['id', 'password']})
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async login(
|
||||
@requestBody({
|
||||
description: 'The input of login function',
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {exclude: ['id', 'isAdmin', 'name']})
|
||||
},
|
||||
}
|
||||
}) credentials: Pick<User, 'email' | 'password'>,
|
||||
): Promise<{ token: string, user: Omit<User, 'id' | 'password'> }> {
|
||||
// ensure the user exists, and the password is correct
|
||||
const user = await this.userService.verifyCredentials(credentials);
|
||||
// convert a User object into a UserProfile object (reduced set of properties)
|
||||
const userProfile = this.userService.convertToUserProfile(user);
|
||||
|
||||
// create a JSON Web Token based on the user profile
|
||||
const token = await this.jwtService.generateToken(userProfile);
|
||||
return {token, user};
|
||||
}
|
||||
|
||||
@post('/users/logout', {
|
||||
responses: {
|
||||
'204': {
|
||||
description: 'Logged out',
|
||||
},
|
||||
},
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async logout(@inject(RestBindings.Http.REQUEST) request: Request): Promise<void> {
|
||||
const split = request.headers.authorization?.split(' ');
|
||||
if (split && split.length > 1) {
|
||||
if (this.jwtService.revokeToken) {
|
||||
await this.jwtService.revokeToken(split[1]);
|
||||
} else {
|
||||
console.error('Cannot revoke token');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@get('/users/count')
|
||||
@response(200, {
|
||||
description: 'User model count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async count(
|
||||
@param.where(User) where?: Where<User>,
|
||||
): Promise<Count> {
|
||||
return this.userRepository.count(where);
|
||||
}
|
||||
|
||||
@get('/users')
|
||||
@response(200, {
|
||||
description: 'Array of User model instances',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: getModelSchemaRef(User, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async find(
|
||||
@param.filter(User) filter?: Filter<User>,
|
||||
): Promise<User[]> {
|
||||
return this.userRepository.find(filter);
|
||||
}
|
||||
|
||||
@patch('/users')
|
||||
@response(200, {
|
||||
description: 'User PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async updateAll(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
user: User,
|
||||
@param.where(User) where?: Where<User>,
|
||||
): Promise<Count> {
|
||||
return this.userRepository.updateAll(user, where);
|
||||
}
|
||||
|
||||
@get('/users/{id}')
|
||||
@response(200, {
|
||||
description: 'User model instance',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async findById(
|
||||
@param.path.number('id') id: number,
|
||||
@param.filter(User, {exclude: 'where'}) filter?: FilterExcludingWhere<User>
|
||||
): Promise<User> {
|
||||
return this.userRepository.findById(id, filter);
|
||||
}
|
||||
|
||||
@patch('/users/{id}')
|
||||
@response(204, {
|
||||
description: 'User PATCH success',
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async updateById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(User, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
user: User,
|
||||
): Promise<void> {
|
||||
if (id === +this.user.id) {
|
||||
const loggedInUser = await this.userService.findUserById(this.user.id);
|
||||
if (user.isAdmin !== undefined && loggedInUser.isAdmin !== user.isAdmin) {
|
||||
throw new HttpErrors.BadRequest('Cannot change admin status of self');
|
||||
}
|
||||
}
|
||||
await this.userRepository.updateById(id, user);
|
||||
}
|
||||
|
||||
@del('/users/{id}')
|
||||
@response(204, {
|
||||
description: 'User DELETE success',
|
||||
})
|
||||
@authenticate('jwt')
|
||||
async deleteById(@param.path.number('id') id: number): Promise<void> {
|
||||
await this.userRepository.deleteById(id);
|
||||
}
|
||||
}
|
|
@ -2,9 +2,8 @@ import { repository } from '@loopback/repository';
|
|||
import { CourseRepository, SubjectRepository, UserRepository } from '../repositories';
|
||||
import { arg, ID, Int, mutation, query, resolver } from '@loopback/graphql';
|
||||
import { Course } from '../models';
|
||||
import { CourseUpdateInput } from '../graphql-types/input/course-update.input';
|
||||
import { listResponse, ListResponse } from '../graphql-types/list';
|
||||
import { CourseList } from '../graphql-types/course';
|
||||
import { CourseList, CourseUpdateInput } from '../graphql-types/course';
|
||||
|
||||
@resolver(of => Course)
|
||||
export class CourseResolver {
|
||||
|
@ -35,4 +34,10 @@ export class CourseResolver {
|
|||
await this.courseRepo.updateById(input.id, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
@mutation(returns => Boolean)
|
||||
async courseCreate(@arg('course') input: CourseUpdateInput): Promise<boolean> {
|
||||
await this.courseRepo.create(input);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
38
backend/src/graphql-resolvers/fulfillment-mode.resolver.ts
Normal file
38
backend/src/graphql-resolvers/fulfillment-mode.resolver.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { repository } from '@loopback/repository';
|
||||
import { CourseRepository, FulfillmentModeRepository, UserRepository } from '../repositories';
|
||||
import { arg, ID, Int, mutation, query, resolver } from '@loopback/graphql';
|
||||
import { FulfillmentMode } from '../models';
|
||||
import { listResponse, ListResponse } from '../graphql-types/list';
|
||||
import { FulfillmentModeList, FulfillmentModeUpdateInput } from '../graphql-types/fulfillment-mode';
|
||||
|
||||
@resolver(of => FulfillmentMode)
|
||||
export class FulfillmentModeResolver {
|
||||
constructor(
|
||||
@repository('CourseRepository') private courseRepo: CourseRepository,
|
||||
@repository('FulfillmentModeRepository') private fulfillmentModeRepo: FulfillmentModeRepository,
|
||||
@repository('UserRepository') private userRepo: UserRepository
|
||||
) {
|
||||
}
|
||||
|
||||
@query(returns => FulfillmentModeList)
|
||||
async fulfillmentModes(@arg('course', returns => ID) course: number, @arg('offset', returns => Int) offset: number, @arg('limit', returns => Int) limit: number): Promise<ListResponse<FulfillmentMode>> {
|
||||
return listResponse(this.courseRepo.fulfillmentModes(course), offset, limit, FulfillmentModeList);
|
||||
}
|
||||
|
||||
@query(returns => FulfillmentMode)
|
||||
async fulfillmentMode(@arg('id', returns => ID) id: number): Promise<FulfillmentMode> {
|
||||
return await this.fulfillmentModeRepo.findById(id);
|
||||
}
|
||||
|
||||
@mutation(returns => Boolean)
|
||||
async fulfillmentModeUpdate(@arg('input') input: FulfillmentModeUpdateInput): Promise<boolean> {
|
||||
await this.fulfillmentModeRepo.updateById(input.id, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
@mutation(returns => Boolean)
|
||||
async fulfillmentModeCreate(@arg('input') input: FulfillmentModeUpdateInput): Promise<boolean> {
|
||||
await this.fulfillmentModeRepo.create(input);
|
||||
return true;
|
||||
}
|
||||
}
|
38
backend/src/graphql-resolvers/requirement.resolver.ts
Normal file
38
backend/src/graphql-resolvers/requirement.resolver.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { repository } from '@loopback/repository';
|
||||
import { FulfillmentModeRepository, RequirementRepository, UserRepository } from '../repositories';
|
||||
import { arg, ID, Int, mutation, query, resolver } from '@loopback/graphql';
|
||||
import { Requirement } from '../models';
|
||||
import { listResponse, ListResponse } from '../graphql-types/list';
|
||||
import { RequirementList, RequirementUpdateInput } from '../graphql-types/requirement';
|
||||
|
||||
@resolver(of => Requirement)
|
||||
export class RequirementResolver {
|
||||
constructor(
|
||||
@repository('FulfillmentModeRepository') private modeRepo: FulfillmentModeRepository,
|
||||
@repository('RequirementRepository') private requirementRepo: RequirementRepository,
|
||||
@repository('UserRepository') private userRepo: UserRepository
|
||||
) {
|
||||
}
|
||||
|
||||
@query(returns => RequirementList)
|
||||
async requirements(@arg('mode', returns => ID) mode: number, @arg('offset', returns => Int) offset: number, @arg('limit', returns => Int) limit: number): Promise<ListResponse<Requirement>> {
|
||||
return listResponse(this.modeRepo.requirements(mode), offset, limit, RequirementList);
|
||||
}
|
||||
|
||||
@query(returns => Requirement)
|
||||
async requirement(@arg('id', returns => ID) id: number): Promise<Requirement> {
|
||||
return await this.requirementRepo.findById(id);
|
||||
}
|
||||
|
||||
@mutation(returns => Boolean)
|
||||
async requirementUpdate(@arg('requirement') input: RequirementUpdateInput): Promise<boolean> {
|
||||
await this.requirementRepo.updateById(input.id, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
@mutation(returns => Boolean)
|
||||
async requirementCreate(@arg('requirement') input: RequirementUpdateInput): Promise<boolean> {
|
||||
await this.requirementRepo.create(input);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -3,8 +3,7 @@ import { Subject } from '../models';
|
|||
import { SubjectRepository } from '../repositories';
|
||||
import { repository } from '@loopback/repository';
|
||||
import { listResponse, ListResponse } from '../graphql-types/list';
|
||||
import { SubjectList } from '../graphql-types/subject';
|
||||
import { SubjectUpdateInput } from '../graphql-types/input/subject-update.input';
|
||||
import { SubjectList, SubjectUpdateInput } from '../graphql-types/subject';
|
||||
|
||||
@resolver(of => Subject)
|
||||
export class SubjectResolver {
|
||||
|
@ -26,4 +25,10 @@ export class SubjectResolver {
|
|||
await this.subjectRepo.updateById(input.id, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
@mutation(returns => Boolean)
|
||||
async subjectCreate(@arg('subject') input: SubjectUpdateInput): Promise<boolean> {
|
||||
await this.subjectRepo.create(input);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,8 @@ import { TokenServiceBindings, UserServiceBindings } from '@loopback/authenticat
|
|||
import { TokenService } from '@loopback/authentication';
|
||||
import { SecurityBindings, UserProfile } from '@loopback/security';
|
||||
import { genSalt, hash } from 'bcryptjs';
|
||||
import { UserRegisterInput } from '../graphql-types/input/user-register.input';
|
||||
import { validated } from '../helpers';
|
||||
import { LoginResult, UserList } from '../graphql-types/user';
|
||||
import { UserUpdateInput } from '../graphql-types/input/user-update.input';
|
||||
import { LoginResult, UserList, UserRegisterInput, UserUpdateInput } from '../graphql-types/user';
|
||||
import { SzakdolgozatBindings } from '../bindings';
|
||||
import { listResponse } from '../graphql-types/list';
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { ListResponse } from './list';
|
||||
import { Course } from '../models';
|
||||
import { field, Int, objectType } from '@loopback/graphql';
|
||||
import { field, ID, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
|
||||
@objectType()
|
||||
export class CourseList implements ListResponse<Course> {
|
||||
|
@ -9,3 +10,15 @@ export class CourseList implements ListResponse<Course> {
|
|||
@field(returns => [Course])
|
||||
list: Course[];
|
||||
}
|
||||
|
||||
@inputType()
|
||||
export class CourseUpdateInput implements Pick<DataObject<Course>, 'id' | 'semester' | 'alias' | 'subjectId'> {
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
@field()
|
||||
semester?: string;
|
||||
@field()
|
||||
alias?: string;
|
||||
@field()
|
||||
subjectId?: number;
|
||||
}
|
||||
|
|
28
backend/src/graphql-types/fulfillment-mode.ts
Normal file
28
backend/src/graphql-types/fulfillment-mode.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { ListResponse } from './list';
|
||||
import { FulfillmentMode } from '../models';
|
||||
import { field, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
|
||||
@objectType()
|
||||
export class FulfillmentModeList implements ListResponse<FulfillmentMode> {
|
||||
@field(returns => Int)
|
||||
count: number;
|
||||
@field(returns => [FulfillmentMode])
|
||||
list: FulfillmentMode[];
|
||||
}
|
||||
|
||||
@inputType()
|
||||
export class FulfillmentModeUpdateInput implements Omit<DataObject<FulfillmentMode>, 'requirements' | 'courseId'> {
|
||||
@field(returns => Int)
|
||||
id: number;
|
||||
@field()
|
||||
name: string;
|
||||
@field()
|
||||
threshold2: number;
|
||||
@field()
|
||||
threshold3: number;
|
||||
@field()
|
||||
threshold4: number;
|
||||
@field()
|
||||
threshold5: number;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import { field, ID, inputType } from '@loopback/graphql';
|
||||
import { Course } from '../../models';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
|
||||
@inputType()
|
||||
export class CourseUpdateInput implements Pick<DataObject<Course>, 'id' | 'semester' | 'alias' | 'subjectId'> {
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
@field()
|
||||
semester?: string;
|
||||
@field()
|
||||
alias?: string;
|
||||
@field()
|
||||
subjectId?: number;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import { field, ID, inputType } from '@loopback/graphql';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
import { Subject } from '../../models';
|
||||
|
||||
@inputType()
|
||||
export class SubjectUpdateInput implements Pick<DataObject<Subject>, 'id' | 'name' | 'description'> {
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
@field()
|
||||
name?: string;
|
||||
@field()
|
||||
description?: string;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import { field, inputType } from '@loopback/graphql';
|
||||
import { User } from '../../models';
|
||||
import { model, property } from '@loopback/repository';
|
||||
import { UserProperties } from '../user';
|
||||
|
||||
@model()
|
||||
@inputType()
|
||||
export class UserRegisterInput implements Pick<User, 'email' | 'name' | 'password'> {
|
||||
@property(UserProperties.email)
|
||||
@field()
|
||||
email: string;
|
||||
@property(UserProperties.name)
|
||||
@field()
|
||||
name: string;
|
||||
@property(UserProperties.password)
|
||||
@field()
|
||||
password: string;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import { User } from '../../models';
|
||||
import { field, ID, inputType } from '@loopback/graphql';
|
||||
import { UserProperties } from '../user';
|
||||
import { property } from '@loopback/repository';
|
||||
|
||||
@inputType()
|
||||
export class UserUpdateInput implements Partial<Pick<User, 'id' | 'name' | 'email' | 'password' | 'isAdmin'>> {
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
@field({nullable: true})
|
||||
@property(UserProperties.email)
|
||||
email?: string;
|
||||
@field({nullable: true})
|
||||
@property(UserProperties.name)
|
||||
name?: string;
|
||||
@field({nullable: true})
|
||||
@property(UserProperties.password)
|
||||
password?: string;
|
||||
@field({nullable: true})
|
||||
isAdmin?: boolean;
|
||||
}
|
28
backend/src/graphql-types/requirement.ts
Normal file
28
backend/src/graphql-types/requirement.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { ListResponse } from './list';
|
||||
import { Requirement } from '../models';
|
||||
import { field, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
|
||||
@objectType()
|
||||
export class RequirementList implements ListResponse<Requirement> {
|
||||
@field(returns => Int)
|
||||
count: number;
|
||||
@field(returns => [Requirement])
|
||||
list: Requirement[];
|
||||
}
|
||||
|
||||
@inputType()
|
||||
export class RequirementUpdateInput implements Pick<DataObject<Requirement>, 'id' | 'name' | 'description' | 'deadline' | 'minPoints' | 'maxPoints'> {
|
||||
@field(returns => Int)
|
||||
id: number;
|
||||
@field()
|
||||
deadline: Date;
|
||||
@field()
|
||||
name: string;
|
||||
@field()
|
||||
description: string;
|
||||
@field()
|
||||
minPoints: number;
|
||||
@field()
|
||||
maxPoints: number;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { ListResponse } from './list';
|
||||
import { Subject } from '../models';
|
||||
import { field, Int, objectType } from '@loopback/graphql';
|
||||
import { field, ID, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { DataObject } from '@loopback/repository';
|
||||
|
||||
@objectType()
|
||||
export class SubjectList implements ListResponse<Subject> {
|
||||
|
@ -9,3 +10,13 @@ export class SubjectList implements ListResponse<Subject> {
|
|||
@field(returns => [Subject])
|
||||
list: Subject[];
|
||||
}
|
||||
|
||||
@inputType()
|
||||
export class SubjectUpdateInput implements Pick<DataObject<Subject>, 'id' | 'name' | 'description'> {
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
@field()
|
||||
name?: string;
|
||||
@field()
|
||||
description?: string;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { User } from '../models';
|
||||
import { field, Int, objectType } from '@loopback/graphql';
|
||||
import { field, ID, inputType, Int, objectType } from '@loopback/graphql';
|
||||
import { ListResponse } from './list';
|
||||
import { model, property } from '@loopback/repository';
|
||||
|
||||
@objectType()
|
||||
export class UserResult implements Pick<User, 'id' | 'email' | 'name' | 'isAdmin'> {
|
||||
|
@ -60,3 +61,34 @@ export const UserProperties = {
|
|||
hidden: true
|
||||
}
|
||||
};
|
||||
|
||||
@model()
|
||||
@inputType()
|
||||
export class UserRegisterInput implements Pick<User, 'email' | 'name' | 'password'> {
|
||||
@property(UserProperties.email)
|
||||
@field()
|
||||
email: string;
|
||||
@property(UserProperties.name)
|
||||
@field()
|
||||
name: string;
|
||||
@property(UserProperties.password)
|
||||
@field()
|
||||
password: string;
|
||||
}
|
||||
|
||||
@inputType()
|
||||
export class UserUpdateInput implements Partial<Pick<User, 'id' | 'name' | 'email' | 'password' | 'isAdmin'>> {
|
||||
@field(returns => ID)
|
||||
id: number;
|
||||
@field({nullable: true})
|
||||
@property(UserProperties.email)
|
||||
email?: string;
|
||||
@field({nullable: true})
|
||||
@property(UserProperties.name)
|
||||
name?: string;
|
||||
@field({nullable: true})
|
||||
@property(UserProperties.password)
|
||||
password?: string;
|
||||
@field({nullable: true})
|
||||
isAdmin?: boolean;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ import { belongsTo, Entity, hasMany, model, property } from '@loopback/repositor
|
|||
import { Subject } from './subject.model';
|
||||
import { User } from './user.model';
|
||||
import { CourseUser } from './course-user.model';
|
||||
import { Requirement } from './requirement.model';
|
||||
import { field, objectType } from '@loopback/graphql';
|
||||
import { FulfillmentMode } from './fulfillment-mode.model';
|
||||
|
||||
@model()
|
||||
@objectType()
|
||||
|
@ -37,8 +37,8 @@ export class Course extends Entity {
|
|||
@hasMany(() => User, {through: {model: () => CourseUser}})
|
||||
users: User[];
|
||||
|
||||
@hasMany(() => Requirement)
|
||||
requirements: Requirement[];
|
||||
@hasMany(() => FulfillmentMode)
|
||||
fulfillmentModes: FulfillmentMode[];
|
||||
|
||||
constructor(data?: Partial<Course>) {
|
||||
super(data);
|
||||
|
|
68
backend/src/models/fulfillment-mode.model.ts
Normal file
68
backend/src/models/fulfillment-mode.model.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { Entity, hasMany, model, property } from '@loopback/repository';
|
||||
import { Requirement } from './requirement.model';
|
||||
import { field, ID, objectType } from '@loopback/graphql';
|
||||
|
||||
@model()
|
||||
@objectType()
|
||||
export class FulfillmentMode extends Entity {
|
||||
@property({
|
||||
type: 'number',
|
||||
id: true,
|
||||
generated: true,
|
||||
})
|
||||
@field(returns => ID)
|
||||
id?: number;
|
||||
|
||||
@property({
|
||||
type: 'string',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
name: string;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
threshold2: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
threshold3: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
threshold4: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
threshold5: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
})
|
||||
courseId?: number;
|
||||
|
||||
@hasMany(() => Requirement)
|
||||
requirements: Requirement[];
|
||||
|
||||
constructor(data?: Partial<FulfillmentMode>) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
export interface FulfillmentModeRelations {
|
||||
// describe navigational properties here
|
||||
}
|
||||
|
||||
export type FulfillmentModeWithRelations = FulfillmentMode & FulfillmentModeRelations;
|
|
@ -4,3 +4,5 @@ export * from './requirement.model';
|
|||
export * from './course.model';
|
||||
export * from './course-user.model';
|
||||
export * from './rev-token.model';
|
||||
export * from './fulfillment-mode.model';
|
||||
export * from './user-fulfill-requirement.model';
|
||||
|
|
|
@ -1,40 +1,60 @@
|
|||
import { Entity, model, property } from '@loopback/repository';
|
||||
import { field, ID, Int, objectType } from '@loopback/graphql';
|
||||
|
||||
@model()
|
||||
@objectType()
|
||||
export class Requirement extends Entity {
|
||||
@property({
|
||||
type: 'number',
|
||||
id: true,
|
||||
generated: true,
|
||||
})
|
||||
id?: number;
|
||||
@property({
|
||||
type: 'number',
|
||||
id: true,
|
||||
generated: true,
|
||||
})
|
||||
@field(returns => ID)
|
||||
id?: number;
|
||||
|
||||
@property({
|
||||
type: 'string',
|
||||
required: true,
|
||||
})
|
||||
name: string;
|
||||
@property({
|
||||
type: 'string',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
name: string;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
maxPoints: number;
|
||||
@property({
|
||||
type: 'string',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
description: string;
|
||||
|
||||
@property({
|
||||
type: 'string',
|
||||
required: true,
|
||||
})
|
||||
type: string;
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field(returns => Int)
|
||||
minPoints: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
})
|
||||
courseId?: number;
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
@field(returns => Int)
|
||||
maxPoints: number;
|
||||
|
||||
constructor(data?: Partial<Requirement>) {
|
||||
super(data);
|
||||
}
|
||||
@property({
|
||||
type: 'date',
|
||||
required: true,
|
||||
})
|
||||
@field()
|
||||
deadline: Date;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
})
|
||||
fulfillmentModeId?: number;
|
||||
|
||||
constructor(data?: Partial<Requirement>) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
export interface RequirementRelations {
|
||||
|
|
43
backend/src/models/user-fulfill-requirement.model.ts
Normal file
43
backend/src/models/user-fulfill-requirement.model.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { Entity, model, property } from '@loopback/repository';
|
||||
|
||||
@model()
|
||||
export class UserFulfillRequirement extends Entity {
|
||||
@property({
|
||||
type: 'number',
|
||||
id: true,
|
||||
generated: true,
|
||||
})
|
||||
id?: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
required: true,
|
||||
})
|
||||
points: number;
|
||||
|
||||
@property({
|
||||
type: 'date',
|
||||
required: true,
|
||||
})
|
||||
dateTime: string;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
})
|
||||
userId?: number;
|
||||
|
||||
@property({
|
||||
type: 'number',
|
||||
})
|
||||
requirementId?: number;
|
||||
|
||||
constructor(data?: Partial<UserFulfillRequirement>) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserFulfillRequirementRelations {
|
||||
// describe navigational properties here
|
||||
}
|
||||
|
||||
export type UserFulfillRequirementWithRelations = UserFulfillRequirement & UserFulfillRequirementRelations;
|
|
@ -3,6 +3,8 @@ import { Course } from './course.model';
|
|||
import { CourseUser } from './course-user.model';
|
||||
import { field, objectType } from '@loopback/graphql';
|
||||
import { UserProperties } from '../graphql-types/user';
|
||||
import { Requirement } from './requirement.model';
|
||||
import { UserFulfillRequirement } from './user-fulfill-requirement.model';
|
||||
|
||||
@model()
|
||||
@objectType()
|
||||
|
@ -34,6 +36,9 @@ export class User extends Entity {
|
|||
//@field()
|
||||
courses: Course[];
|
||||
|
||||
@hasMany(() => Requirement, {through: {model: () => UserFulfillRequirement}})
|
||||
completedRequirements: Requirement[];
|
||||
|
||||
constructor(data?: Partial<User>) {
|
||||
super(data);
|
||||
}
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
import { inject, Getter } from '@loopback/core';
|
||||
import {
|
||||
DefaultCrudRepository,
|
||||
repository,
|
||||
BelongsToAccessor,
|
||||
HasManyThroughRepositoryFactory,
|
||||
HasManyRepositoryFactory
|
||||
} from '@loopback/repository';
|
||||
import { Getter, inject } from '@loopback/core';
|
||||
import { BelongsToAccessor, repository } from '@loopback/repository';
|
||||
import { DatabaseDataSource } from '../datasources';
|
||||
import { Course, CourseRelations, Subject, User, CourseUser, Requirement } from '../models';
|
||||
import { Course, CourseRelations, CourseUser, FulfillmentMode, Subject, User } from '../models';
|
||||
import { SubjectRepository } from './subject.repository';
|
||||
import { CourseUserRepository } from './course-user.repository';
|
||||
import { UserRepository } from './user.repository';
|
||||
import { RequirementRepository } from './requirement.repository';
|
||||
import { FulfillmentModeRepository } from './fulfillment-mode.repository';
|
||||
import { CustomCrudRepository, CustomHasManyRepositoryFactory, CustomHasManyThroughRepositoryFactory } from './custom-has-many-repository';
|
||||
|
||||
export class CourseRepository extends DefaultCrudRepository<Course,
|
||||
export class CourseRepository extends CustomCrudRepository<Course,
|
||||
typeof Course.prototype.id,
|
||||
CourseRelations> {
|
||||
|
||||
public readonly subject: BelongsToAccessor<Subject, typeof Course.prototype.id>;
|
||||
|
||||
public readonly users: HasManyThroughRepositoryFactory<User, typeof User.prototype.id,
|
||||
public readonly users: CustomHasManyThroughRepositoryFactory<User, typeof User.prototype.id,
|
||||
CourseUser,
|
||||
typeof Course.prototype.id>;
|
||||
|
||||
public readonly requirements: HasManyRepositoryFactory<Requirement, typeof Course.prototype.id>;
|
||||
public readonly fulfillmentModes: CustomHasManyRepositoryFactory<FulfillmentMode, typeof Course.prototype.id>;
|
||||
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource, @repository.getter('SubjectRepository') protected subjectRepositoryGetter: Getter<SubjectRepository>, @repository.getter('CourseUserRepository') protected courseUserRepositoryGetter: Getter<CourseUserRepository>, @repository.getter('UserRepository') protected userRepositoryGetter: Getter<UserRepository>, @repository.getter('RequirementRepository') protected requirementRepositoryGetter: Getter<RequirementRepository>,
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource,
|
||||
@repository.getter('SubjectRepository') protected subjectRepositoryGetter: Getter<SubjectRepository>,
|
||||
@repository.getter('CourseUserRepository') protected courseUserRepositoryGetter: Getter<CourseUserRepository>,
|
||||
@repository.getter('UserRepository') protected userRepositoryGetter: Getter<UserRepository>,
|
||||
@repository.getter('FulfillmentModeRepository') protected fulfillmentModeRepositoryGetter: Getter<FulfillmentModeRepository>,
|
||||
) {
|
||||
super(Course, dataSource);
|
||||
this.requirements = this.createHasManyRepositoryFactoryFor('requirements', requirementRepositoryGetter,);
|
||||
this.registerInclusionResolver('requirements', this.requirements.inclusionResolver);
|
||||
this.users = this.createHasManyThroughRepositoryFactoryFor('users', userRepositoryGetter, courseUserRepositoryGetter,);
|
||||
this.fulfillmentModes = this.createCustomHasManyRepositoryFactoryFor('fulfillmentModes', fulfillmentModeRepositoryGetter, 'courseId');
|
||||
this.registerInclusionResolver('fulfillmentModes', this.fulfillmentModes.inclusionResolver);
|
||||
this.users = this.createCustomHasManyThroughFactoryFor('users', userRepositoryGetter, courseUserRepositoryGetter, 'courseId', 'userId');
|
||||
this.registerInclusionResolver('users', this.users.inclusionResolver);
|
||||
this.subject = this.createBelongsToAccessorFor('subject', subjectRepositoryGetter,);
|
||||
this.registerInclusionResolver('subject', this.subject.inclusionResolver);
|
||||
|
|
21
backend/src/repositories/fulfillment-mode.repository.ts
Normal file
21
backend/src/repositories/fulfillment-mode.repository.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { Getter, inject } from '@loopback/core';
|
||||
import { repository } from '@loopback/repository';
|
||||
import { DatabaseDataSource } from '../datasources';
|
||||
import { FulfillmentMode, FulfillmentModeRelations, Requirement } from '../models';
|
||||
import { RequirementRepository } from './requirement.repository';
|
||||
import { CustomCrudRepository, CustomHasManyRepositoryFactory } from './custom-has-many-repository';
|
||||
|
||||
export class FulfillmentModeRepository extends CustomCrudRepository<FulfillmentMode,
|
||||
typeof FulfillmentMode.prototype.id,
|
||||
FulfillmentModeRelations> {
|
||||
|
||||
public readonly requirements: CustomHasManyRepositoryFactory<Requirement, typeof FulfillmentMode.prototype.id>;
|
||||
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource, @repository.getter('RequirementRepository') protected requirementRepositoryGetter: Getter<RequirementRepository>,
|
||||
) {
|
||||
super(FulfillmentMode, dataSource);
|
||||
this.requirements = this.createCustomHasManyRepositoryFactoryFor('requirements', requirementRepositoryGetter, 'fulfillmentModeId');
|
||||
this.registerInclusionResolver('requirements', this.requirements.inclusionResolver);
|
||||
}
|
||||
}
|
|
@ -4,3 +4,5 @@ export * from './requirement.repository';
|
|||
export * from './course.repository';
|
||||
export * from './course-user.repository';
|
||||
export * from './rev-token.repository';
|
||||
export * from './fulfillment-mode.repository';
|
||||
export * from './user-fulfill-requirement.repository';
|
||||
|
|
|
@ -6,9 +6,9 @@ import { RevToken, RevTokenRelations } from '../models';
|
|||
export class RevTokenRepository extends DefaultCrudRepository<RevToken,
|
||||
typeof RevToken.prototype.token,
|
||||
RevTokenRelations> {
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource,
|
||||
) {
|
||||
super(RevToken, dataSource);
|
||||
}
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource,
|
||||
) {
|
||||
super(RevToken, dataSource);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { inject } from '@loopback/core';
|
||||
import { DatabaseDataSource } from '../datasources';
|
||||
import { UserFulfillRequirement, UserFulfillRequirementRelations } from '../models';
|
||||
import { CustomCrudRepository } from './custom-has-many-repository';
|
||||
|
||||
export class UserFulfillRequirementRepository extends CustomCrudRepository<UserFulfillRequirement,
|
||||
typeof UserFulfillRequirement.prototype.id,
|
||||
UserFulfillRequirementRelations> {
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource,
|
||||
) {
|
||||
super(UserFulfillRequirement, dataSource);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { Getter, inject } from '@loopback/core';
|
||||
import { repository } from '@loopback/repository';
|
||||
import { HasManyThroughRepositoryFactory, repository } from '@loopback/repository';
|
||||
import { DatabaseDataSource } from '../datasources';
|
||||
import { Course, CourseUser, User, UserRelations } from '../models';
|
||||
import { Course, CourseUser, Requirement, User, UserFulfillRequirement, UserRelations } from '../models';
|
||||
import { SubjectRepository } from './subject.repository';
|
||||
import { CourseUserRepository } from './course-user.repository';
|
||||
import { CourseRepository } from './course.repository';
|
||||
import { CustomCrudRepository, CustomHasManyThroughRepositoryFactory } from './custom-has-many-repository';
|
||||
import { UserFulfillRequirementRepository } from './user-fulfill-requirement.repository';
|
||||
import { RequirementRepository } from './requirement.repository';
|
||||
|
||||
export class UserRepository extends CustomCrudRepository<User,
|
||||
typeof User.prototype.id,
|
||||
|
@ -15,10 +17,16 @@ export class UserRepository extends CustomCrudRepository<User,
|
|||
CourseUser,
|
||||
typeof User.prototype.id>;
|
||||
|
||||
public readonly completedRequirements: HasManyThroughRepositoryFactory<Requirement, typeof Requirement.prototype.id,
|
||||
UserFulfillRequirement,
|
||||
typeof User.prototype.id>;
|
||||
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource, @repository.getter('SubjectRepository') protected subjectRepositoryGetter: Getter<SubjectRepository>, @repository.getter('CourseUserRepository') protected courseUserRepositoryGetter: Getter<CourseUserRepository>, @repository.getter('CourseRepository') protected courseRepositoryGetter: Getter<CourseRepository>,
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource, @repository.getter('SubjectRepository') protected subjectRepositoryGetter: Getter<SubjectRepository>, @repository.getter('CourseUserRepository') protected courseUserRepositoryGetter: Getter<CourseUserRepository>, @repository.getter('CourseRepository') protected courseRepositoryGetter: Getter<CourseRepository>, @repository.getter('UserFulfillRequirementRepository') protected userFulfillRequirementRepositoryGetter: Getter<UserFulfillRequirementRepository>, @repository.getter('RequirementRepository') protected requirementRepositoryGetter: Getter<RequirementRepository>,
|
||||
) {
|
||||
super(User, dataSource);
|
||||
this.completedRequirements = this.createHasManyThroughRepositoryFactoryFor('completedRequirements', requirementRepositoryGetter, userFulfillRequirementRepositoryGetter,);
|
||||
this.registerInclusionResolver('completedRequirements', this.completedRequirements.inclusionResolver);
|
||||
this.courses = this.createCustomHasManyThroughFactoryFor('courses', courseRepositoryGetter, courseUserRepositoryGetter, 'userId', 'courseId');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,3 +31,7 @@ query Course($id: ID!) {
|
|||
mutation EditCourse($input: CourseUpdateInput!) {
|
||||
courseUpdate(course: $input)
|
||||
}
|
||||
|
||||
mutation CreateCourse($input: CourseUpdateInput!) {
|
||||
courseCreate(course: $input)
|
||||
}
|
||||
|
|
32
frontend/src/app/graphql/requirement.graphql
Normal file
32
frontend/src/app/graphql/requirement.graphql
Normal file
|
@ -0,0 +1,32 @@
|
|||
query RequirementList($mode: ID!, $limit: Int!, $offset: Int!) {
|
||||
requirements(mode: $mode, limit: $limit, offset: $offset) {
|
||||
count
|
||||
list {
|
||||
id
|
||||
name
|
||||
description
|
||||
deadline
|
||||
minPoints
|
||||
maxPoints
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query Requirement($id: ID!) {
|
||||
requirement(id: $id) {
|
||||
id
|
||||
name
|
||||
description
|
||||
deadline
|
||||
minPoints
|
||||
maxPoints
|
||||
}
|
||||
}
|
||||
|
||||
mutation EditRequirement($input: RequirementUpdateInput!) {
|
||||
requirementUpdate(requirement: $input)
|
||||
}
|
||||
|
||||
mutation CreateRequirement($input: RequirementUpdateInput!) {
|
||||
requirementCreate(requirement: $input)
|
||||
}
|
|
@ -20,3 +20,7 @@ query Subject($id: ID!) {
|
|||
mutation EditSubject($input: SubjectUpdateInput!) {
|
||||
subjectUpdate(subject: $input)
|
||||
}
|
||||
|
||||
mutation CreateSubject($input: SubjectUpdateInput!) {
|
||||
subjectCreate(subject: $input)
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<app-list [gql]="listGQL"></app-list>
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RequirementListComponent } from './requirement-list.component';
|
||||
|
||||
describe('RequirementsListComponent', () => {
|
||||
let component: RequirementListComponent;
|
||||
let fixture: ComponentFixture<RequirementListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RequirementListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RequirementListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { RequirementListGQL } from '../../services/graphql';
|
||||
|
||||
@Component({
|
||||
selector: 'app-requirement-list',
|
||||
templateUrl: './requirement-list.component.html',
|
||||
styleUrls: ['./requirement-list.component.css']
|
||||
})
|
||||
export class RequirementListComponent implements OnInit {
|
||||
|
||||
constructor(public listGQL: RequirementListGQL) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
15
frontend/src/app/requirements/requirements.module.ts
Normal file
15
frontend/src/app/requirements/requirements.module.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RequirementListComponent } from './requirement-list/requirement-list.component';
|
||||
import { SharedComponentsModule } from '../shared-components/shared-components.module';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [RequirementListComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedComponentsModule
|
||||
]
|
||||
})
|
||||
export class RequirementsModule {
|
||||
}
|
Loading…
Reference in a new issue