Merge pull request #4 from Worklenz/fix/migration-remove

Fix/migration remove
This commit is contained in:
Chamika J
2024-05-17 11:19:57 +05:30
committed by GitHub
29 changed files with 17 additions and 337 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -10,11 +10,11 @@ SOCKET_IO_CORS=http://localhost:4200
SERVER_CORS=*
# Database
DB_USER=DATABASE_USER_NAME_HERE
DB_USER=DATABASE_USER_HERE # default : worklenz_backend (update "user-permission.sql" if needed)
DB_PASSWORD=DATABASE_PASSWORD_HERE
DB_NAME=DATABASE_NAME_HERE
DB_HOST=DATABASE_HOST_HERE # localhost
DB_PORT=DATABASE_PORT_HERE
DB_NAME=DATABASE_NAME_HERE # default : worklenz_db
DB_HOST=DATABASE_HOST_HERE # default : localhost
DB_PORT=DATABASE_PORT_HERE # default : 5432
DB_MAX_CLIENTS=50
# Google Login
@@ -43,8 +43,8 @@ JWT_SECRET=JWT_SECRET_CODE_HERE
# AWS
AWS_REGION="us-west-2"
AWS_ACCESS_KEY_ID="AWS_ACCESS_KEY_ID_HERE" # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
AWS_SECRET_ACCESS_KEY="AWS_SECRET_ACCESS_KEY_HERE" # "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
AWS_ACCESS_KEY_ID="AWS_ACCESS_KEY_ID_HERE"
AWS_SECRET_ACCESS_KEY="AWS_SECRET_ACCESS_KEY_HERE"
# S3 Credentials
REGION="us-west-2"
@@ -53,3 +53,5 @@ S3_URL="S3_URL_HERE"
S3_ACCESS_KEY_ID="S3_ACCESS_KEY_ID_HERE"
S3_SECRET_ACCESS_KEY="S3_SECRET_ACCESS_KEY_HERE"
# SES email
SOURCE_EMAIL="SOURCE_EMAIL_HERE" #Worklenz <noreply@worklenz.com>

View File

@@ -1,7 +1,11 @@
-- Default ROLE : worklenz_client
-- Default USER : worklenz_backend
-- Change DATABASE_NAME, ROLE, PASSWORD and USER as needed.
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
CREATE ROLE worklenz_client;
GRANT CONNECT ON DATABASE "DATABASE_NAME" TO worklenz_client;
GRANT CONNECT ON DATABASE 'DATABASE_NAME' TO worklenz_client;
GRANT INSERT, SELECT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO worklenz_client;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO worklenz_client;

View File

@@ -698,47 +698,4 @@ export default class ProjectsController extends WorklenzControllerBase {
return result.rows || [];
}
public static async updateExistPhaseColors() {
const q = `SELECT id, name FROM project_phases`;
const phases = await db.query(q);
phases.rows.forEach((phase) => {
phase.color_code = getColor(phase.name);
});
const body = {
phases: phases.rows
};
const q2 = `SELECT update_existing_phase_colors($1)`;
await db.query(q2, [JSON.stringify(body)]);
}
public static async updateExistSortOrder() {
const q = `SELECT id, project_id FROM project_phases ORDER BY name`;
const phases = await db.query(q);
const sortNumbers: any = {};
phases.rows.forEach(phase => {
const projectId = phase.project_id;
if (!sortNumbers[projectId]) {
sortNumbers[projectId] = 0;
}
phase.sort_number = sortNumbers[projectId]++;
});
const body = {
phases: phases.rows
};
const q2 = `SELECT update_existing_phase_sort_order($1)`;
await db.query(q2, [JSON.stringify(body)]);
// return phases;
}
}

View File

@@ -52,83 +52,6 @@ export default class ScheduleControllerV2 extends ScheduleTasksControllerBase {
private static GLOBAL_START_DATE = moment().format("YYYY-MM-DD");
private static GLOBAL_END_DATE = moment().format("YYYY-MM-DD");
// Migrate data
@HandleExceptions()
public static async migrate(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const getDataq = `SELECT p.id,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT tmiv.team_member_id,
tmiv.user_id,
LEAST(
(SELECT MIN(LEAST(start_date, end_date)) AS start_date
FROM tasks
INNER JOIN tasks_assignees ta ON tasks.id = ta.task_id
WHERE archived IS FALSE
AND project_id = p.id
AND ta.team_member_id = tmiv.team_member_id),
(SELECT MIN(twl.created_at - INTERVAL '1 second' * twl.time_spent) AS ll_start_date
FROM task_work_log twl
INNER JOIN tasks t ON twl.task_id = t.id AND t.archived IS FALSE
WHERE t.project_id = p.id
AND twl.user_id = tmiv.user_id)
) AS lowest_date,
GREATEST(
(SELECT MAX(GREATEST(start_date, end_date)) AS end_date
FROM tasks
INNER JOIN tasks_assignees ta ON tasks.id = ta.task_id
WHERE archived IS FALSE
AND project_id = p.id
AND ta.team_member_id = tmiv.team_member_id),
(SELECT MAX(twl.created_at - INTERVAL '1 second' * twl.time_spent) AS ll_end_date
FROM task_work_log twl
INNER JOIN tasks t ON twl.task_id = t.id AND t.archived IS FALSE
WHERE t.project_id = p.id
AND twl.user_id = tmiv.user_id)
) AS greatest_date
FROM project_members pm
INNER JOIN team_member_info_view tmiv
ON pm.team_member_id = tmiv.team_member_id
WHERE project_id = p.id) rec) AS members
FROM projects p
WHERE team_id IS NOT NULL
AND p.id NOT IN (SELECT project_id FROM archived_projects)`;
const projectMembersResults = await db.query(getDataq);
const projectMemberData = projectMembersResults.rows;
const arrayToInsert = [];
for (const data of projectMemberData) {
if (data.members.length) {
for (const member of data.members) {
const body = {
project_id: data.id,
team_member_id: member.team_member_id,
allocated_from: member.lowest_date ? member.lowest_date : null,
allocated_to: member.greatest_date ? member.greatest_date : null
};
if (body.allocated_from && body.allocated_to) arrayToInsert.push(body);
}
}
}
const insertArray = JSON.stringify(arrayToInsert);
const insertFunctionCall = `SELECT migrate_member_allocations($1)`;
await db.query(insertFunctionCall, [insertArray]);
return res.status(200).send(new ServerResponse(true, ""));
}
private static async getFirstLastDates(teamId: string, userId: string) {
const q = `SELECT MIN(LEAST(allocated_from, allocated_to)) AS start_date,
MAX(GREATEST(allocated_from, allocated_to)) AS end_date,

View File

@@ -17,7 +17,6 @@ scheduleApiRouter.get("/projects/:id", idParamValidator, safeControllerFunction(
scheduleApiRouter.get("/project-member/:id", idParamValidator, safeControllerFunction(ScheduleControllerV2.getSingleProjectMember));
scheduleApiRouter.get("/refresh/project-indicator/:id", idParamValidator, safeControllerFunction(ScheduleControllerV2.getSingleProjectIndicator));
scheduleApiRouter.get("/tasks-by-member/:id", idParamValidator, safeControllerFunction(getList));
scheduleApiRouter.get("/migrate/member-allocations", safeControllerFunction(ScheduleControllerV2.migrate));
scheduleApiRouter.put("/bulk/delete-member-allocations", safeControllerFunction(ScheduleControllerV2.deleteMemberAllocations));
export default scheduleApiRouter;

View File

@@ -11,11 +11,6 @@ import projectMemberValidator from "../../middlewares/validators/project-member-
const projectsApiRouter = express.Router();
// db changes. One time only
projectsApiRouter.get("/update-exist-phase-colors", safeControllerFunction(ProjectsController.updateExistPhaseColors));
projectsApiRouter.get("/update-exist-sort-order", safeControllerFunction(ProjectsController.updateExistSortOrder));
projectsApiRouter.post("/", teamOwnerOrAdminValidator, projectsBodyValidator, safeControllerFunction(ProjectsController.create));
projectsApiRouter.get("/", safeControllerFunction(ProjectsController.get));
projectsApiRouter.get("/my-task-projects", safeControllerFunction(ProjectsController.getMyProjectsToTasks));

View File

@@ -79,7 +79,7 @@ export async function sendEmail(email: IEmail): Promise<string | null> {
}
}
},
Source: "SOURCE_EMAIL_HERE" // Ex: Worklenz <noreply@worklenz.com>
Source: process.env.SOURCE_EMAIL // Ex: Worklenz <noreply@worklenz.com>
});
const res = await sesClient.send(command);

View File

@@ -1,12 +1,12 @@
{
"name": "worklenz",
"version": "1.4.16",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "worklenz",
"version": "1.4.16",
"version": "1.0.0",
"dependencies": {
"@angular/animations": "^16.2.0",
"@angular/cdk": "^16.2.0",

View File

@@ -3,18 +3,8 @@ import {RouterModule, Routes} from '@angular/router';
import {ProjectsComponent} from './projects/projects.component';
import {ProjectOverviewComponent} from './project-insights/project-overview/project-overview.component';
import {ProjectViewComponent} from "./project-view/project-view.component";
import {MigrateTemplatesComponent} from "./projects/migrate-templates/migrate-templates.component";
import {
MigrateMemberAllocationsComponent
} from "./projects/migrate-member-allocations/migrate-member-allocations.component";
import {MigrateProjectPhasesComponent} from "./projects/migrate-project-phases/migrate-project-phases.component";
import {MigratePhaseSortOrderComponent} from "./projects/migrate-phase-sort-order/migrate-phase-sort-order.component";
const routes: Routes = [
{path: 'migrate', component: MigrateTemplatesComponent},
{path: 'migrate/member-allocations', component: MigrateMemberAllocationsComponent},
{path: 'migrate/project-phases', component: MigrateProjectPhasesComponent},
{path: 'migrate/phase-sort-order', component: MigratePhaseSortOrderComponent},
{path: '', component: ProjectsComponent},
{path: 'member/:id', component: ProjectOverviewComponent},
{path: ':id', component: ProjectViewComponent},

View File

@@ -105,7 +105,6 @@ import {
import {
ProjectTemplateImportDrawerComponent
} from "@admin/components/project-template-import-drawer/project-template-import-drawer.component";
import { MigrateTemplatesComponent } from './projects/migrate-templates/migrate-templates.component';
import {WorkloadGaantChartV2Component} from './components-v2/workload-gaant-chart-v2/workload-gaant-chart-v2.component';
import {TaskNameComponent} from './components-v2/workload-gaant-chart-v2/components/task-name/task-name.component';
import {WLStartDateComponent} from './components-v2/workload-gaant-chart-v2/components/start-date/start-date.component';
@@ -131,10 +130,6 @@ import { MemberTaskAddContainerComponent } from './components-v2/workload-gaant-
import { TaskListHeaderComponent } from './components-v2/workload-gaant-chart-v2/components/task-list-header/task-list-header.component';
import { WLContextMenuComponent } from './components-v2/workload-gaant-chart-v2/components/context-menu/context-menu.component';
import {GanttChartV2Module} from "../modules/roadmap-v2/gantt-chart-v2.module";
import { MigrateMemberAllocationsComponent } from './projects/migrate-member-allocations/migrate-member-allocations.component';
import { MigrateProjectPhasesComponent } from './projects/migrate-project-phases/migrate-project-phases.component';
import { MigratePhaseSortOrderComponent } from './projects/migrate-phase-sort-order/migrate-phase-sort-order.component';
@NgModule({
declarations: [
@@ -171,11 +166,7 @@ import { MigratePhaseSortOrderComponent } from './projects/migrate-phase-sort-or
OverviewTabComponent,
MemberTaskAddContainerComponent,
TaskListHeaderComponent,
WLContextMenuComponent,
MigrateTemplatesComponent,
MigrateMemberAllocationsComponent,
MigrateProjectPhasesComponent,
MigratePhaseSortOrderComponent
WLContextMenuComponent
],
imports: [
CommonModule,

View File

@@ -1,21 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MigrateMemberAllocationsComponent } from './migrate-member-allocations.component';
describe('MigrateMemberAllocationsComponent', () => {
let component: MigrateMemberAllocationsComponent;
let fixture: ComponentFixture<MigrateMemberAllocationsComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MigrateMemberAllocationsComponent]
});
fixture = TestBed.createComponent(MigrateMemberAllocationsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,21 +0,0 @@
import {Component, OnInit} from '@angular/core';
import {ScheduleApiService} from "@api/schedule-api.service";
@Component({
selector: 'worklenz-migrate-member-allocations',
templateUrl: './migrate-member-allocations.component.html',
styleUrls: ['./migrate-member-allocations.component.scss']
})
export class MigrateMemberAllocationsComponent implements OnInit{
constructor(
private readonly api: ScheduleApiService
) {}
async ngOnInit() {
const res = await this.api.migrateAllocations();
if(res.done) {
alert("Drop migrate_member_allocations postgres function.")
}
}
}

View File

@@ -1,21 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MigratePhaseSortOrderComponent } from './migrate-phase-sort-order.component';
describe('MigratePhaseSortOrderComponent', () => {
let component: MigratePhaseSortOrderComponent;
let fixture: ComponentFixture<MigratePhaseSortOrderComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MigratePhaseSortOrderComponent]
});
fixture = TestBed.createComponent(MigratePhaseSortOrderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,19 +0,0 @@
import { Component } from '@angular/core';
import {ProjectsApiService} from "@api/projects-api.service";
@Component({
selector: 'worklenz-migrate-phase-sort-order',
templateUrl: './migrate-phase-sort-order.component.html',
styleUrls: ['./migrate-phase-sort-order.component.scss']
})
export class MigratePhaseSortOrderComponent {
constructor(
private api: ProjectsApiService,
) {}
async ngOnInit() {
setTimeout(async () => {
await this.api.updateExistSortOrder();
},500);
}
}

View File

@@ -1,21 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MigrateProjectPhasesComponent } from './migrate-project-phases.component';
describe('MigrateProjectPhasesComponent', () => {
let component: MigrateProjectPhasesComponent;
let fixture: ComponentFixture<MigrateProjectPhasesComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MigrateProjectPhasesComponent]
});
fixture = TestBed.createComponent(MigrateProjectPhasesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,21 +0,0 @@
import {Component, OnInit} from '@angular/core';
import {ReportingApiService} from "../../../reporting/reporting-api.service";
import {ProjectsApiService} from "@api/projects-api.service";
@Component({
selector: 'worklenz-migrate-project-phases',
templateUrl: './migrate-project-phases.component.html',
styleUrls: ['./migrate-project-phases.component.scss']
})
export class MigrateProjectPhasesComponent implements OnInit{
constructor(
private api: ProjectsApiService,
) {}
async ngOnInit() {
setTimeout(async () => {
await this.api.updateExistPhaseColors();
},500);
}
}

View File

@@ -1,21 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MigrateTemplatesComponent } from './migrate-templates.component';
describe('MigrateTemplatesComponent', () => {
let component: MigrateTemplatesComponent;
let fixture: ComponentFixture<MigrateTemplatesComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MigrateTemplatesComponent]
});
fixture = TestBed.createComponent(MigrateTemplatesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,19 +0,0 @@
import {Component} from '@angular/core';
import {ProjectTemplateApiService} from "@api/project-template-api.service";
@Component({
selector: 'worklenz-migrate-templates',
templateUrl: './migrate-templates.component.html',
styleUrls: ['./migrate-templates.component.scss']
})
export class MigrateTemplatesComponent {
constructor(
private readonly api: ProjectTemplateApiService
) {
this.import();
}
async import() {
await this.api.createTemplates();
}
}

View File

@@ -123,12 +123,4 @@ export class ProjectsApiService extends APIServiceBase {
return this._get(this.http, `${this.root}/archive-all/${id}`);
}
public async updateExistPhaseColors(): Promise<IServerResponse<any>> {
return this._get(this.http, `${this.root}/update-exist-phase-colors`);
}
public async updateExistSortOrder(): Promise<IServerResponse<any>> {
return this._get(this.http, `${this.root}/update-exist-sort-order`);
}
}

View File

@@ -51,9 +51,4 @@ export class ScheduleApiService extends APIServiceBase {
return this._get(this.http, `${this.root}/tasks-by-member/${config.id}${q}`);
}
// This function only calls a single time.
migrateAllocations(): Promise<IServerResponse<any>> {
return this._get(this.http, `${this.root}/migrate/member-allocations`)
}
}