Merge pull request #4 from Worklenz/fix/migration-remove
Fix/migration remove
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
4
worklenz-frontend/package-lock.json
generated
4
worklenz-frontend/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<p>migrate-phase-sort-order works!</p>
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<p>migrate-project-phases works!</p>
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<p>migrate-templates works!</p>
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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`)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user