Skip to content

Commit

Permalink
Merge pull request #42 from PolyHx/features/sponsor-view
Browse files Browse the repository at this point in the history
Sponsor view
  • Loading branch information
JulienDuf authored Apr 5, 2019
2 parents 5366b4c + c53d164 commit 31f7580
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 35 deletions.
11 changes: 11 additions & 0 deletions src/modules/database/attendees/attendees.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ export class AttendeesController {
});
}

@Get(':id/cv/url')
@Permissions('csgames-api:get-all:attendee')
public async getCvUrlById(@Param('id') id: string): Promise<{ url: string }> {
const attendee = await this.attendeesService.findOne({ _id: id });
if (attendee.cv) {
return { url: await this.storageService.getDownloadUrl(attendee.cv) };
} else {
return { url: null };
}
}

@Put()
@Permissions('csgames-api:update:attendee')
public async update(@UploadedFile() file, @User() user: UserModel,
Expand Down
8 changes: 8 additions & 0 deletions src/modules/database/events/events.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Permissions } from '../../../decorators/permission.decorator';
import { User } from '../../../decorators/user.decorator';
import { CodeExceptionFilter } from '../../../filters/code-error/code.filter';
import { PermissionsGuard } from '../../../guards/permission.guard';
import { BufferInterceptor } from '../../../interceptors/buffer.interceptor';
import { DataGridDownloadInterceptor } from '../../../interceptors/data-grid-download.interceptor';
import { UserModel } from '../../../models/user.model';
import { ArrayPipe } from '../../../pipes/array.pipe';
Expand Down Expand Up @@ -141,6 +142,13 @@ export class EventsController {
return await this.eventsService.getAttendeesData(eventId, type, roles);
}

@Get('attendee/cv')
@UseInterceptors(new BufferInterceptor("application/zip"))
@Permissions('csgames-api:get-all:attendee')
public async getAttendeeCv(@EventId() eventId: string): Promise<any> {
return await this.eventsService.getAttendeeCv(eventId);
}

@Post('sms')
@Permissions('csgames-api:update:event')
public async sendSms(@EventId() eventId: string, @Body(new ValidationPipe()) dto: SendSmsDto) {
Expand Down
5 changes: 3 additions & 2 deletions src/modules/database/events/events.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { EventsController } from './events.controller';
import { EventsSchema } from './events.model';
import { EventsService } from './events.service';
import { AttendeesModule } from '../attendees/attendees.module';
import { STSModule } from '@polyhx/nest-services';
import { StorageModule, STSModule } from '@polyhx/nest-services';
import { EmailModule } from '../../email/email.module';
import { TeamsSchema } from '../teams/teams.model';
import { MessagingModule } from '../../messaging/messaging.module';
Expand Down Expand Up @@ -35,7 +35,8 @@ import { FlashOutsModule } from '../flash-out/flash-out.module';
forwardRef(() => TeamsModule),
MessagingModule,
NotificationsModule,
FlashOutsModule
FlashOutsModule,
StorageModule
],
controllers: [
EventsController
Expand Down
42 changes: 34 additions & 8 deletions src/modules/database/events/events.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { StorageService } from '@polyhx/nest-services';
import * as AdmZip from 'adm-zip';
import * as mongoose from 'mongoose';
import { Model } from 'mongoose';
import { isNullOrUndefined } from 'util';
Expand All @@ -8,17 +10,17 @@ import { BaseService } from '../../../services/base.service';
import { CreateActivityDto } from '../activities/activities.dto';
import { Activities } from '../activities/activities.model';
import { ActivitiesService } from '../activities/activities.service';
import { UpdateAttendeeDto } from '../attendees/attendees.dto';
import { AttendeeNotifications, Attendees } from '../attendees/attendees.model';
import { AttendeesService } from '../attendees/attendees.service';
import { Competitions, CompetitionsUtils } from '../competitions/competitions.model';
import { Notifications } from '../notifications/notifications.model';
import { NotificationsService } from '../notifications/notifications.service';
import { AddScannedAttendee, AddSponsorDto, CreateEventDto, SendNotificationDto } from './events.dto';
import { Schools } from '../schools/schools.model';
import { Teams } from '../teams/teams.model';
import { AddSponsorDto, CreateEventDto, SendNotificationDto } from './events.dto';
import { AttendeeAlreadyRegisteredException, EventNotFoundException, UserNotAttendeeException } from './events.exception';
import { Events, EventSponsorDetails } from './events.model';
import { UpdateAttendeeDto } from '../attendees/attendees.dto';
import { Teams } from '../teams/teams.model';
import { Schools } from '../schools/schools.model';

export interface EventScore {
overall: TeamScore[];
Expand All @@ -39,6 +41,7 @@ export class EventsService extends BaseService<Events, CreateEventDto> {
@InjectModel('competitions') private readonly competitionsModel: Model<Competitions>,
private readonly attendeeService: AttendeesService,
private readonly activitiesService: ActivitiesService,
private readonly storageService: StorageService,
private readonly notificationService: NotificationsService) {
super(eventsModel);
}
Expand Down Expand Up @@ -85,7 +88,7 @@ export class EventsService extends BaseService<Events, CreateEventDto> {
}

let registered = false;
if (role === "admin" || role === "volunteer" || role === "director") {
if (role === "admin" || role === "volunteer" || role === "director" || role === "sponsor") {
registered = true;
}

Expand Down Expand Up @@ -368,6 +371,26 @@ export class EventsService extends BaseService<Events, CreateEventDto> {
return await this.attendeeService.getFromEvent(eventId, attendees, type);
}

public async getAttendeeCv(eventId: string): Promise<any> {
const attendees = await this.getAttendeesData(eventId, 'json', ['attendee', 'captain', 'godparent']);

let files = await this.storageService.getDirectory('cv');
files = files.filter(file => attendees.some(a => a.cv === file.name));

const zip = new AdmZip();
for (const file of files) {
const attendee = attendees.find(a => a.cv === file.name);
if (!attendee) {
continue;
}

const [buffer] = await file.download();
zip.addFile(`${attendee.firstName}_${attendee.lastName}-${file.metadata.metadata.name}`, buffer);
}

return zip.toBuffer();
}

public async getScore(eventId: string): Promise<EventScore> {
const competitions = await this.competitionsModel.find({
event: eventId
Expand Down Expand Up @@ -413,7 +436,7 @@ export class EventsService extends BaseService<Events, CreateEventDto> {
return {
...x,
name,
results: x.results.map(result => {
results: x.results.filter(x => x.teamId.school).map(result => {
const team = result.teamId as Teams;
return {
teamId: team._id.toHexString(),
Expand All @@ -429,7 +452,10 @@ export class EventsService extends BaseService<Events, CreateEventDto> {

private async getOverallScore(eventId: string, competitions: Competitions[]): Promise<TeamScore[]> {
const teams = await this.teamsModel.find({
event: eventId
event: eventId,
school: {
$ne: null
}
}).select(['_id', 'name', 'school'])
.populate([{
path: 'school',
Expand Down
21 changes: 17 additions & 4 deletions src/modules/database/puzzle-heroes/puzzle-heroes.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/comm
import { InjectModel } from '@nestjs/mongoose';
import { BaseService } from '../../../services/base.service';
import { DateUtils } from '../../../utils/date.utils';
import { Sponsors } from '../sponsors/sponsors.model';
import { PuzzleHeroes, PuzzleHeroesUtils } from './puzzle-heroes.model';
import * as mongoose from 'mongoose';
import { Model } from 'mongoose';
Expand Down Expand Up @@ -259,14 +260,26 @@ export class PuzzleHeroesService extends BaseService<PuzzleHeroes, PuzzleHeroes>
const team = await this.teamsModel.findOne({
event: eventId,
_id: s.value
});

const school = await this.schoolsModel.findById(team.school);
}).populate([{
model: 'teams',
path: 'team',
select: ['name']
}, {
model: 'sponsors',
path: 'sponsor',
select: ['name']
}]).exec();

if (user.role === 'sponsor' && !team.sponsor) {
return null;
} else if (!user.role.endsWith('admin') && !team.school) {
return null;
}

return {
teamId: team._id.toHexString(),
teamName: team.name,
schoolName: school.name,
schoolName: team.school ? (team.school as Schools).name : (team.sponsor as Sponsors).name,
score: s.score
};
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class TeamAlreadyExistException extends CodeException {

export class TeamDoesntExistException extends CodeException {
constructor () {
super(Code.TEAM_ALREADY_EXIST);
super(Code.TEAM_DOESNT_EXIST);
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/modules/database/registrations/registrations.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CreateAttendeeDto } from '../attendees/attendees.dto';
export class CreateRegistrationDto {
@IsString()
@IsNotEmpty()
@IsIn(['attendee', 'captain', 'godparent'])
@IsIn(['attendee', 'captain', 'godparent', 'sponsor'])
@ApiModelProperty({ required: true })
role: string;

Expand Down Expand Up @@ -36,6 +36,12 @@ export class CreateRegistrationDto {
@ApiModelProperty({ required: true })
schoolId: string;

@IsMongoId()
@IsNotEmpty()
@ValidateIf(x => x.role === 'sponsor')
@ApiModelProperty({ required: true })
sponsorId: string;

@IsNumber()
@ValidateIf(x => x.role === 'captain')
@IsNotEmpty()
Expand Down
64 changes: 49 additions & 15 deletions src/modules/database/registrations/registrations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Registrations } from './registrations.model';
export class RegistrationsService {
private roleTemplate = {
attendee: 'attendee_account_creation',
sponsor: 'attendee_account_creation',
captain: 'captain_account_creation',
godparent: 'godparent_account_creation'
};
Expand All @@ -41,8 +42,9 @@ export class RegistrationsService {
throw new AttendeeAlreadyExistException();
}

await this.validateTeam(dto.teamName, dto.role, eventId);

if (dto.role !== 'sponsor') {
await this.validateTeam(dto.teamName, dto.role, eventId);
}
const attendee = await this.attendeeService.create({
email: dto.email.toLowerCase(),
firstName: dto.firstName,
Expand All @@ -55,20 +57,10 @@ export class RegistrationsService {
});
registration = await registration.save();

if (dto.role === 'captain' && (role === 'admin' || role === 'super-admin')) {
await this.teamsService.createTeam({
name: dto.teamName,
event: eventId,
school: dto.schoolId,
attendeeId: attendee._id,
maxMembersNumber: dto.maxMembersNumber
});
if (dto.role === 'sponsor') {
await this.addSponsor(dto, role, eventId, attendee);
} else {
await this.teamsService.update({name: dto.teamName, event: eventId}, {
$push: {
attendees: attendee._id
}
} as any);
await this.addAttendee(dto, role, eventId, attendee);
}

await this.eventService.addAttendee(eventId, attendee, dto.role);
Expand Down Expand Up @@ -223,6 +215,48 @@ export class RegistrationsService {
}
}

private async addAttendee(dto: CreateRegistrationDto, role: string, eventId: string, attendee: Attendees) {
if (dto.role === 'captain' && (role === 'admin' || role === 'super-admin')) {
await this.teamsService.createTeam({
name: dto.teamName,
event: eventId,
school: dto.schoolId,
sponsor: null,
attendeeId: attendee._id,
maxMembersNumber: dto.maxMembersNumber
});
} else {
await this.teamsService.update({name: dto.teamName, event: eventId}, {
$push: {
attendees: attendee._id
}
} as any);
}
}

private async addSponsor(dto: CreateRegistrationDto, role: string, eventId: string, attendee: Attendees) {
const team = await this.teamsService.findOne({
sponsor: dto.sponsorId,
event: eventId
});
if (!team) {
await this.teamsService.createTeam({
name: dto.teamName,
event: eventId,
school: null,
sponsor: dto.sponsorId,
attendeeId: attendee._id,
maxMembersNumber: dto.maxMembersNumber
});
} else {
await this.teamsService.update({sponsor: dto.sponsorId, event: eventId}, {
$push: {
attendees: attendee._id
}
} as any);
}
}

private async fetchRoles() {
const roles = await this.stsService.getRoles().then(x => x.roles);
if (!roles) {
Expand Down
32 changes: 31 additions & 1 deletion src/modules/database/teams/teams.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiModelProperty } from "@nestjs/swagger";
import { IsMongoId, IsNotEmpty, IsString, IsOptional, MaxLength, IsNumber } from "class-validator";
import { IsMongoId, IsNotEmpty, IsString, MaxLength, IsNumber, ValidateIf, IsOptional } from 'class-validator';

export class CreateTeamDto {
@IsString()
Expand All @@ -15,9 +15,17 @@ export class CreateTeamDto {
@IsMongoId()
@IsNotEmpty()
@IsString()
@ValidateIf(x => !x.sponsor)
@ApiModelProperty({required: true})
school: string;

@IsMongoId()
@IsNotEmpty()
@IsString()
@ValidateIf(x => !x.school)
@ApiModelProperty({required: true})
sponsor: string;

@IsMongoId()
@IsNotEmpty()
@IsString()
Expand All @@ -36,4 +44,26 @@ export class UpdateTeamDto {
@MaxLength(30)
@ApiModelProperty({required: true})
name: string;

@IsOptional()
@IsNumber()
@IsNotEmpty()
@ApiModelProperty({ required: true })
maxMembersNumber: number;

@IsOptional()
@IsMongoId()
@IsNotEmpty()
@IsString()
@ValidateIf(x => !x.sponsor)
@ApiModelProperty({required: true})
school: string;

@IsOptional()
@IsMongoId()
@IsNotEmpty()
@IsString()
@ValidateIf(x => !x.school)
@ApiModelProperty({required: true})
sponsor: string;
}
7 changes: 6 additions & 1 deletion src/modules/database/teams/teams.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import * as mongoose from "mongoose";
import { Attendees } from "../attendees/attendees.model";
import { Events } from "../events/events.model";
import { Schools } from "../schools/schools.model";
import { Sponsors } from '../sponsors/sponsors.model';

export interface Teams extends mongoose.Document {
_id: mongoose.Types.ObjectId;
name: string;
attendees: (Attendees | mongoose.Types.ObjectId | string)[];
event: Events | mongoose.Types.ObjectId | string;
school: Schools | mongoose.Types.ObjectId | string;
sponsor: Sponsors | mongoose.Types.ObjectId | string;
present: boolean;
maxMembersNumber: number;
}
Expand All @@ -30,9 +32,12 @@ export const TeamsSchema = new mongoose.Schema({
},
school: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'schools'
},
sponsor: {
type: mongoose.Schema.Types.ObjectId,
ref: 'sponsors'
},
maxMembersNumber: {
type: Number,
required: true
Expand Down
Loading

0 comments on commit 31f7580

Please sign in to comment.