Browse Source

Feature/add user id to tag database schema (#3837)

* Add user id to tag database schema

* Update changelog
pull/3838/head
Thomas Kaul 7 days ago
committed by GitHub
parent
commit
85cc72627b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 11
      CHANGELOG.md
  2. 2
      apps/api/src/app/info/info.service.ts
  3. 1
      apps/api/src/app/platform/platform.controller.ts
  4. 1
      apps/api/src/app/tag/tag.controller.ts
  5. 3
      apps/api/src/app/tag/tag.service.ts
  6. 2
      apps/api/src/app/user/user.service.ts
  7. 7
      apps/api/src/services/tag/tag.service.ts
  8. 4
      apps/client/src/app/components/admin-platform/admin-platform.component.ts
  9. 14
      apps/client/src/app/components/admin-tag/admin-tag.component.html
  10. 6
      apps/client/src/app/components/admin-tag/admin-tag.component.ts
  11. 12
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  12. 6
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  13. 4
      libs/common/src/lib/permissions.ts
  14. 1
      package.json
  15. 11
      prisma/migrations/20240928171744_added_user_to_tag/migration.sql
  16. 6
      prisma/schema.prisma

11
CHANGELOG.md

@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Added
- Added read `permissions` to the `Platform` model
- Added read `permissions` to the `Tag` model
- Added `userId` to the `Tag` database schema
### Changed ### Changed
- Considered the availability of the date range selector in the assistant per view - Considered the availability of the date range selector in the assistant per view
@ -17,6 +23,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Upgraded `prisma` from version `5.19.1` to `5.20.0` - Upgraded `prisma` from version `5.19.1` to `5.20.0`
- Upgraded `webpack-bundle-analyzer` from version `4.10.1` to `4.10.2` - Upgraded `webpack-bundle-analyzer` from version `4.10.1` to `4.10.2`
### Fixed
- Fixed the content height of the create or update platform dialog in the admin control
- Fixed the content height of the create or update tag dialog in the admin control
## 2.110.0 - 2024-09-24 ## 2.110.0 - 2024-09-24
### Changed ### Changed

2
apps/api/src/app/info/info.service.ts

@ -114,7 +114,7 @@ export class InfoService {
}), }),
this.getStatistics(), this.getStatistics(),
this.getSubscriptions(), this.getSubscriptions(),
this.tagService.get() this.tagService.getPublic()
]); ]);
if (isUserSignupEnabled) { if (isUserSignupEnabled) {

1
apps/api/src/app/platform/platform.controller.ts

@ -26,6 +26,7 @@ export class PlatformController {
public constructor(private readonly platformService: PlatformService) {} public constructor(private readonly platformService: PlatformService) {}
@Get() @Get()
@HasPermission(permissions.readPlatforms)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getPlatforms() { public async getPlatforms() {
return this.platformService.getPlatformsWithAccountCount(); return this.platformService.getPlatformsWithAccountCount();

1
apps/api/src/app/tag/tag.controller.ts

@ -26,6 +26,7 @@ export class TagController {
public constructor(private readonly tagService: TagService) {} public constructor(private readonly tagService: TagService) {}
@Get() @Get()
@HasPermission(permissions.readTags)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getTags() { public async getTags() {
return this.tagService.getTagsWithActivityCount(); return this.tagService.getTagsWithActivityCount();

3
apps/api/src/app/tag/tag.service.ts

@ -56,10 +56,11 @@ export class TagService {
} }
}); });
return tagsWithOrderCount.map(({ _count, id, name }) => { return tagsWithOrderCount.map(({ _count, id, name, userId }) => {
return { return {
id, id,
name, name,
userId,
activityCount: _count.orders activityCount: _count.orders
}; };
}); });

2
apps/api/src/app/user/user.service.ts

@ -70,7 +70,7 @@ export class UserService {
}, },
where: { userId: id } where: { userId: id }
}), }),
this.tagService.getByUser(id) this.tagService.getInUseByUser(id)
]); ]);
let systemMessage: SystemMessage; let systemMessage: SystemMessage;

7
apps/api/src/services/tag/tag.service.ts

@ -6,15 +6,18 @@ import { Injectable } from '@nestjs/common';
export class TagService { export class TagService {
public constructor(private readonly prismaService: PrismaService) {} public constructor(private readonly prismaService: PrismaService) {}
public async get() { public async getPublic() {
return this.prismaService.tag.findMany({ return this.prismaService.tag.findMany({
orderBy: { orderBy: {
name: 'asc' name: 'asc'
},
where: {
userId: null
} }
}); });
} }
public async getByUser(userId: string) { public async getInUseByUser(userId: string) {
return this.prismaService.tag.findMany({ return this.prismaService.tag.findMany({
orderBy: { orderBy: {
name: 'asc' name: 'asc'

4
apps/client/src/app/components/admin-platform/admin-platform.component.ts

@ -139,7 +139,7 @@ export class AdminPlatformComponent implements OnInit, OnDestroy {
url: null url: null
} }
}, },
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', height: this.deviceType === 'mobile' ? '97.5vh' : undefined,
width: this.deviceType === 'mobile' ? '100vw' : '50rem' width: this.deviceType === 'mobile' ? '100vw' : '50rem'
}); });
@ -176,7 +176,7 @@ export class AdminPlatformComponent implements OnInit, OnDestroy {
url url
} }
}, },
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', height: this.deviceType === 'mobile' ? '97.5vh' : undefined,
width: this.deviceType === 'mobile' ? '100vw' : '50rem' width: this.deviceType === 'mobile' ? '100vw' : '50rem'
}); });

14
apps/client/src/app/components/admin-tag/admin-tag.component.html

@ -34,6 +34,20 @@
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="userId">
<th
*matHeaderCellDef
class="px-1"
mat-header-cell
mat-sort-header="userId"
>
<ng-container i18n>User</ng-container>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
<span class="text-monospace">{{ element.userId }}</span>
</td>
</ng-container>
<ng-container matColumnDef="activities"> <ng-container matColumnDef="activities">
<th <th
*matHeaderCellDef *matHeaderCellDef

6
apps/client/src/app/components/admin-tag/admin-tag.component.ts

@ -36,7 +36,7 @@ export class AdminTagComponent implements OnInit, OnDestroy {
public dataSource: MatTableDataSource<Tag> = new MatTableDataSource(); public dataSource: MatTableDataSource<Tag> = new MatTableDataSource();
public deviceType: string; public deviceType: string;
public displayedColumns = ['name', 'activities', 'actions']; public displayedColumns = ['name', 'userId', 'activities', 'actions'];
public tags: Tag[]; public tags: Tag[];
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -138,7 +138,7 @@ export class AdminTagComponent implements OnInit, OnDestroy {
name: null name: null
} }
}, },
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', height: this.deviceType === 'mobile' ? '97.5vh' : undefined,
width: this.deviceType === 'mobile' ? '100vw' : '50rem' width: this.deviceType === 'mobile' ? '100vw' : '50rem'
}); });
@ -174,7 +174,7 @@ export class AdminTagComponent implements OnInit, OnDestroy {
name name
} }
}, },
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', height: this.deviceType === 'mobile' ? '97.5vh' : undefined,
width: this.deviceType === 'mobile' ? '100vw' : '50rem' width: this.deviceType === 'mobile' ? '100vw' : '50rem'
}); });

12
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -158,10 +158,10 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
{ id: this.data.symbol, type: 'SYMBOL' } { id: this.data.symbol, type: 'SYMBOL' }
]; ];
this.tagsAvailable = tags.map(({ id, name }) => { this.tagsAvailable = tags.map((tag) => {
return { return {
id, ...tag,
name: translate(name) name: translate(tag.name)
}; };
}); });
@ -320,10 +320,10 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
this.sectors = {}; this.sectors = {};
this.SymbolProfile = SymbolProfile; this.SymbolProfile = SymbolProfile;
this.tags = tags.map(({ id, name }) => { this.tags = tags.map((tag) => {
return { return {
id, ...tag,
name: translate(name) name: translate(tag.name)
}; };
}); });

6
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts

@ -81,10 +81,10 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.currencies = currencies; this.currencies = currencies;
this.defaultDateFormat = getDateFormatString(this.locale); this.defaultDateFormat = getDateFormatString(this.locale);
this.platforms = platforms; this.platforms = platforms;
this.tagsAvailable = tags.map(({ id, name }) => { this.tagsAvailable = tags.map((tag) => {
return { return {
id, ...tag,
name: translate(name) name: translate(tag.name)
}; };
}); });

4
libs/common/src/lib/permissions.ts

@ -31,6 +31,8 @@ export const permissions = {
enableSubscriptionInterstitial: 'enableSubscriptionInterstitial', enableSubscriptionInterstitial: 'enableSubscriptionInterstitial',
enableSystemMessage: 'enableSystemMessage', enableSystemMessage: 'enableSystemMessage',
impersonateAllUsers: 'impersonateAllUsers', impersonateAllUsers: 'impersonateAllUsers',
readPlatforms: 'readPlatforms',
readTags: 'readTags',
reportDataGlitch: 'reportDataGlitch', reportDataGlitch: 'reportDataGlitch',
toggleReadOnlyMode: 'toggleReadOnlyMode', toggleReadOnlyMode: 'toggleReadOnlyMode',
updateAccount: 'updateAccount', updateAccount: 'updateAccount',
@ -64,6 +66,8 @@ export function getPermissions(aRole: Role): string[] {
permissions.deletePlatform, permissions.deletePlatform,
permissions.deleteTag, permissions.deleteTag,
permissions.deleteUser, permissions.deleteUser,
permissions.readPlatforms,
permissions.readTags,
permissions.updateAccount, permissions.updateAccount,
permissions.updateAuthDevice, permissions.updateAuthDevice,
permissions.updateOrder, permissions.updateOrder,

1
package.json

@ -37,6 +37,7 @@
"ng": "nx", "ng": "nx",
"nx": "nx", "nx": "nx",
"postinstall": "prisma generate", "postinstall": "prisma generate",
"prisma": "prisma",
"replace-placeholders-in-build": "node ./replace.build.js", "replace-placeholders-in-build": "node ./replace.build.js",
"start": "node dist/apps/api/main", "start": "node dist/apps/api/main",
"start:client": "nx run client:copy-assets && nx run client:serve --configuration=development-en --hmr -o", "start:client": "nx run client:copy-assets && nx run client:serve --configuration=development-en --hmr -o",

11
prisma/migrations/20240928171744_added_user_to_tag/migration.sql

@ -0,0 +1,11 @@
-- DropIndex
DROP INDEX "Tag_name_key";
-- AlterTable
ALTER TABLE "Tag" ADD COLUMN "userId" TEXT;
-- CreateIndex
CREATE UNIQUE INDEX "Tag_name_userId_key" ON "Tag"("name", "userId");
-- AddForeignKey
ALTER TABLE "Tag" ADD CONSTRAINT "Tag_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

6
prisma/schema.prisma

@ -213,9 +213,12 @@ model Subscription {
model Tag { model Tag {
id String @id @default(uuid()) id String @id @default(uuid())
name String @unique name String
orders Order[] orders Order[]
userId String?
User User? @relation(fields: [userId], onDelete: Cascade, references: [id])
@@unique([name, userId])
@@index([name]) @@index([name])
} }
@ -236,6 +239,7 @@ model User {
Order Order[] Order Order[]
Settings Settings? Settings Settings?
Subscription Subscription[] Subscription Subscription[]
Tag Tag[]
@@index([accessToken]) @@index([accessToken])
@@index([createdAt]) @@index([createdAt])

Loading…
Cancel
Save