Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat#1496/activity api #1776

Merged
merged 3 commits into from
Jul 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,18 @@ import { DealModule } from './deal/deal.module';
import { HelpCenterAuthorModule } from './help-center-author/help-center-author.module';
import { OrganizationSprintModule } from './organization-sprint/organization-sprint.module';
import { GoalKpiModule } from './goal-kpi/goal-kpi.module';
import { MulterModule } from '@nestjs/platform-express';
import { FileStorage } from './core/file-storage';

@Module({
imports: [
ServeStaticModule.forRoot({
rootPath: path.resolve(process.cwd(), 'apps', 'api', 'public'),
serveRoot: '/public/'
}),
MulterModule.register({
dest: FileStorage.rootPath
}),
RouterModule.forRoutes([
{
path: '',
Expand Down
6 changes: 6 additions & 0 deletions apps/api/src/app/core/entities/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger';
import { BaseEntityModel as IBaseEntityModel } from '@gauzy/models';

export abstract class Base implements IBaseEntityModel {
constructor(input?: any) {
if (input) {
Object.assign(this, input);
}
}

@ApiPropertyOptional({ type: String })
@PrimaryGeneratedColumn('uuid')
id?: string;
Expand Down
54 changes: 54 additions & 0 deletions apps/api/src/app/core/file-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as path from 'path';
import * as moment from 'moment';
import * as fs from 'fs';
import * as multer from 'multer';
import { environment } from '@env-api/environment';

export interface FileStorageOption {
dest: string;
prefix?: string;
filename?: string | CallableFunction;
}

export class FileStorage {
static rootPath = path.join(process.cwd(), 'apps', 'api');

static default(option: FileStorageOption) {
return FileStorage.local(option);
}

static url(filePath: string) {
if (filePath && filePath.startsWith('http')) {
return filePath;
}
return filePath ? environment.baseUrl + '/' + filePath : null;
}

static local({ dest, filename, prefix }: FileStorageOption) {
return multer.diskStorage({
destination: (req, file, callback) => {
fs.mkdirSync(path.join(FileStorage.rootPath, dest), {
recursive: true
});
callback(null, path.join(FileStorage.rootPath, dest));
},
filename: (req, file, callback) => {
let fileNameString = '';
const ext = file.originalname.split('.').pop();
if (filename) {
if (typeof filename === 'string') {
fileNameString = filename;
} else {
fileNameString = filename(file, ext);
}
} else {
fileNameString = `gauzy-${prefix}-${moment().unix()}-${parseInt(
'' + Math.random() * 1000,
10
)}.${ext}`;
}
callback(null, fileNameString);
}
});
}
}
11 changes: 9 additions & 2 deletions apps/api/src/app/hubstaff/hubstaff.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,8 @@ export class HubstaffService {

const gauzyScreenshot = await this.commandBus.execute(
new ScreenshotCreateCommand({
fullUrl: full_url,
thumbUrl: thumb_url,
file: full_url,
thumb: thumb_url,
recordedAt: recorded_at,
activityTimestamp: time_slot,
employeeId: employee.gauzyId
Expand Down Expand Up @@ -658,12 +658,16 @@ export class HubstaffService {
organizationId
);

const time = moment(date).format('YYYY-MM-DD');
date = moment(date).format('HH:mm:ss');

const gauzyActivity = await this.commandBus.execute(
new ActivityCreateCommand({
title: site,
duration: tracked,
type: 'URL',
date,
time,
projectId,
employeeId: employee.gauzyId
})
Expand Down Expand Up @@ -768,12 +772,15 @@ export class HubstaffService {
integrationId,
organizationId
);
const time = moment(date).format('YYYY-MM-DD');
date = moment(date).format('HH:mm:ss');

const gauzyActivity = await this.commandBus.execute(
new ActivityCreateCommand({
title: name,
duration: tracked,
type: 'APP',
time,
date,
projectId,
employeeId: employee.gauzyId
Expand Down
29 changes: 22 additions & 7 deletions apps/api/src/app/timesheet/activity.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ export class Activity extends Base implements IActivity {
@ApiProperty({ type: Employee })
@ManyToOne(() => Employee)
@JoinColumn()
employee: Employee;
employee?: Employee;

@ApiProperty({ type: String, readOnly: true })
@RelationId((timeSlot: TimeSlot) => timeSlot.employee)
@RelationId((activity: Activity) => activity.employee)
@Column()
readonly employeeId: string;
employeeId?: string;

@ApiProperty({ type: OrganizationProjects })
@ManyToOne(() => OrganizationProjects, { nullable: true })
Expand All @@ -45,7 +45,17 @@ export class Activity extends Base implements IActivity {
@ApiProperty({ type: String, readOnly: true })
@RelationId((activity: Activity) => activity.project)
@Column({ nullable: true })
readonly projectId?: string;
projectId?: string;

@ApiProperty({ type: TimeSlot })
@ManyToOne(() => TimeSlot, { nullable: true })
@JoinColumn()
timeSlot?: TimeSlot;

@ApiProperty({ type: String, readOnly: true })
@RelationId((activity: Activity) => activity.timeSlot)
@Column({ nullable: true })
timeSlotId?: string;

@ApiProperty({ type: Task })
@ManyToOne(() => Task, { nullable: true })
Expand All @@ -55,7 +65,7 @@ export class Activity extends Base implements IActivity {
@ApiProperty({ type: String, readOnly: true })
@RelationId((activity: Activity) => activity.task)
@Column({ nullable: true })
readonly taskId?: string;
taskId?: string;

@ApiProperty({ type: String })
@IsString()
Expand All @@ -65,7 +75,12 @@ export class Activity extends Base implements IActivity {
@ApiProperty({ type: 'date' })
@IsDateString()
@CreateDateColumn({ type: 'date' })
date: Date;
date: string;

@ApiProperty({ type: 'time' })
@IsDateString()
@CreateDateColumn({ type: 'time' })
time: string;

@ApiProperty({ type: Number })
@IsNumber()
Expand All @@ -83,7 +98,7 @@ export class Activity extends Base implements IActivity {
@IsEnum(TimeLogSourceEnum)
@IsString()
@Column({ default: TimeLogSourceEnum.BROWSER })
source: string;
source?: string;

@ApiProperty({ type: 'timestamptz' })
@IsDateString()
Expand Down
6 changes: 4 additions & 2 deletions apps/api/src/app/timesheet/activity/activities.seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export const createRandomActivities = async (connection: Connection) => {
activity.project = project;
activity.task = task;
activity.title = appName;
activity.date = date;
activity.date = moment(date).format('YYYY-MM-DD');
activity.time = moment(date).format('HH:mm:ss');
activity.duration = faker.random.number(100);
activity.type = ActivityType.APP;

Expand All @@ -66,7 +67,8 @@ export const createRandomActivities = async (connection: Connection) => {
activity.project = project;
activity.task = task;
activity.title = url;
activity.date = date;
activity.date = moment(date).format('YYYY-MM-DD');
activity.time = moment(date).format('HH:mm:ss');
activity.duration = faker.random.number(100);
activity.type = ActivityType.URL;

Expand Down
29 changes: 27 additions & 2 deletions apps/api/src/app/timesheet/activity/activity.controller.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { Controller, UseGuards, HttpStatus, Get, Query } from '@nestjs/common';
import {
Controller,
UseGuards,
HttpStatus,
Get,
Query,
Post
} from '@nestjs/common';
import { Activity } from '../activity.entity';
import { CrudController } from '../../core/crud/crud.controller';
import { ActivityService } from './activity.service';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { IGetActivitiesInput } from '@gauzy/models';
import { IGetActivitiesInput, IBulkActivitiesInput } from '@gauzy/models';

@ApiTags('Activity')
@UseGuards(AuthGuard('jwt'))
Expand All @@ -22,6 +29,24 @@ export class ActivityController extends CrudController<Activity> {
})
@Get('/')
async getActivites(@Query() request: IGetActivitiesInput) {
const defaultParams: Partial<IGetActivitiesInput> = {
page: 0,
limit: 30
};

request = Object.assign({}, defaultParams, request);

return this.activityService.getActivites(request);
}

@ApiOperation({ summary: 'Save bulk Activites' })
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description:
'Invalid input, The response body may contain clues as to what went wrong'
})
@Post('/bulk')
async bulkSaveActivites(@Query() request: IBulkActivitiesInput) {
return this.activityService.bulkSave(request.activities);
}
}
Loading