privilege

This commit is contained in:
Evert Prants 2022-04-15 22:00:02 +03:00
parent 8cff63a0a7
commit 3f399320b6
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
15 changed files with 129 additions and 10 deletions

View File

@ -9,6 +9,8 @@ dotenv.config();
const CONFIG_ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'dev'; const CONFIG_ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
const CONFIG_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`; const CONFIG_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`;
const CONFIG_PATH = join(process.cwd(), CONFIG_FILENAME); const CONFIG_PATH = join(process.cwd(), CONFIG_FILENAME);
const config = toml.parse(readFileSync(CONFIG_PATH, { encoding: 'utf-8' })); const config = JSON.parse(
JSON.stringify(toml.parse(readFileSync(CONFIG_PATH, { encoding: 'utf-8' }))),
);
module.exports = config.database; module.exports = config.database;

View File

@ -21,6 +21,7 @@ import { DatabaseModule } from './modules/objects/database/database.module';
import { EmailModule } from './modules/objects/email/email.module'; import { EmailModule } from './modules/objects/email/email.module';
import { OAuth2ClientModule } from './modules/objects/oauth2-client/oauth2-client.module'; import { OAuth2ClientModule } from './modules/objects/oauth2-client/oauth2-client.module';
import { OAuth2TokenModule } from './modules/objects/oauth2-token/oauth2-token.module'; import { OAuth2TokenModule } from './modules/objects/oauth2-token/oauth2-token.module';
import { PrivilegeModule } from './modules/objects/privilege/privilege.module';
import { UploadModule } from './modules/objects/upload/upload.module'; import { UploadModule } from './modules/objects/upload/upload.module';
import { UserModule } from './modules/objects/user/user.module'; import { UserModule } from './modules/objects/user/user.module';
import { UtilityModule } from './modules/utility/utility.module'; import { UtilityModule } from './modules/utility/utility.module';
@ -48,6 +49,7 @@ import { UtilityModule } from './modules/utility/utility.module';
OAuth2Module, OAuth2Module,
TwoFactorModule, TwoFactorModule,
SettingsModule, SettingsModule,
PrivilegeModule,
], ],
controllers: [AppController], controllers: [AppController],
providers: [AppService, CSRFMiddleware], providers: [AppService, CSRFMiddleware],

View File

@ -11,6 +11,7 @@
--main-background: #314550; --main-background: #314550;
--main: #2e6b81; --main: #2e6b81;
--main-light: #519eb9; --main-light: #519eb9;
--main-darkish: #006683;
--main-darker: #005b74; --main-darker: #005b74;
--main-dark: #042b3a; --main-dark: #042b3a;

View File

@ -17,9 +17,15 @@
} }
&__nav { &__nav {
display: flex;
padding: 2rem 0rem; padding: 2rem 0rem;
background-color: var(--main-darker); background-color: var(--main-darker);
&-content {
display: flex;
flex-grow: 1;
}
ul { ul {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -43,13 +49,17 @@
&.active { &.active {
border-right-color: var(--main-light); border-right-color: var(--main-light);
font-weight: bold; background-color: var(--main-darkish);
} }
&:focus { &:focus {
outline: 4px solid var(--focus-outline); outline: 4px solid var(--focus-outline);
} }
} }
&:last-child {
margin-top: auto;
}
} }
} }
} }
@ -177,6 +187,7 @@
padding: 0; padding: 0;
background-color: var(--main-darker); background-color: var(--main-darker);
box-shadow: 0px 6px 62px -14px rgba(0, 0, 0, 0.45); box-shadow: 0px 6px 62px -14px rgba(0, 0, 0, 0.45);
flex-direction: column;
& > .settings__nav-content { & > .settings__nav-content {
display: block; display: block;

30
src/fe/ts/upload.ts Normal file
View File

@ -0,0 +1,30 @@
export class UploadInput {
private wrap: HTMLElement;
private inner: HTMLElement;
private hover = false;
constructor(public input: HTMLInputElement) {}
initialize(): void {
this.wrap = document.createElement('div');
this.wrap.classList.add('upload__wrapper');
this.inner = document.createElement('div');
this.inner.classList.add('upload');
this.wrap.appendChild(this.inner);
this.inner.addEventListener('dragenter', () => {
this.hover = true;
this.inner.classList.add('upload--hovered');
});
this.inner.addEventListener('dragleave', () => {
this.hover = false;
this.inner.classList.remove('upload--hovered');
});
this.inner.addEventListener('dragover', () => {});
this.input.parentElement.appendChild(this.wrap);
}
}

View File

@ -13,6 +13,7 @@ export class UserMiddleware implements NestMiddleware {
// TODO: check for bans // TODO: check for bans
const userObj = await this.userService.getByUUID(req.session.user, [ const userObj = await this.userService.getByUUID(req.session.user, [
'picture', 'picture',
'privileges',
]); ]);
if (userObj && userObj.activated) { if (userObj && userObj.activated) {
req.user = userObj; req.user = userObj;

View File

@ -67,7 +67,7 @@ export class OAuth2Controller {
const token = res.locals.accessToken as OAuth2AccessToken; const token = res.locals.accessToken as OAuth2AccessToken;
const user = await this._service.userService.getById( const user = await this._service.userService.getById(
token.user_id as number, token.user_id as number,
['picture'], ['picture', 'privileges'],
); );
if (!user) { if (!user) {
@ -101,6 +101,13 @@ export class OAuth2Controller {
userData.image_file = user.picture.file; userData.image_file = user.picture.file;
} }
if (
token.scope.includes('privileges') ||
(token.scope.includes('user:privileges') && user.privileges?.length)
) {
userData.privileges = user.privileges;
}
return userData; return userData;
} }
} }

View File

@ -7,11 +7,9 @@ import {
Render, Render,
Req, Req,
Res, Res,
Session,
} from '@nestjs/common'; } from '@nestjs/common';
import { Throttle } from '@nestjs/throttler'; import { Throttle } from '@nestjs/throttler';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { SessionData } from 'express-session';
import { UserService } from 'src/modules/objects/user/user.service'; import { UserService } from 'src/modules/objects/user/user.service';
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service'; import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
import { RegisterDto } from './register.interfaces'; import { RegisterDto } from './register.interfaces';

View File

@ -0,0 +1,10 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Privilege {
@PrimaryGeneratedColumn()
id: number;
@Column({ type: 'text', nullable: false })
name: string;
}

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { DatabaseModule } from '../database/database.module';
import { privilegeProviders } from './privilege.providers';
import { PrivilegeService } from './privilege.service';
@Module({
imports: [DatabaseModule],
providers: [...privilegeProviders, PrivilegeService],
exports: [PrivilegeService],
})
export class PrivilegeModule {}

View File

@ -0,0 +1,10 @@
import { Connection } from 'typeorm';
import { Privilege } from './privilege.entity';
export const privilegeProviders = [
{
provide: 'PRIVILEGE_REPOSITORY',
useFactory: (connection: Connection) => connection.getRepository(Privilege),
inject: ['DATABASE_CONNECTION'],
},
];

View File

@ -0,0 +1,11 @@
import { Inject, Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Privilege } from './privilege.entity';
@Injectable()
export class PrivilegeService {
constructor(
@Inject('PRIVILEGE_REPOSITORY')
private privilegeRepository: Repository<Privilege>,
) {}
}

View File

@ -2,11 +2,13 @@ import {
Column, Column,
CreateDateColumn, CreateDateColumn,
Entity, Entity,
JoinTable,
ManyToMany,
ManyToOne, ManyToOne,
OneToOne,
PrimaryGeneratedColumn, PrimaryGeneratedColumn,
UpdateDateColumn, UpdateDateColumn,
} from 'typeorm'; } from 'typeorm';
import { Privilege } from '../privilege/privilege.entity';
import { Upload } from '../upload/upload.entity'; import { Upload } from '../upload/upload.entity';
@Entity() @Entity()
@ -54,4 +56,8 @@ export class User {
onUpdate: 'CASCADE', onUpdate: 'CASCADE',
}) })
public picture: Upload; public picture: Upload;
@ManyToMany(() => Privilege)
@JoinTable()
public privileges: Privilege[];
} }

View File

@ -1,13 +1,20 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { DatabaseModule } from '../database/database.module'; import { DatabaseModule } from '../database/database.module';
import { EmailModule } from '../email/email.module'; import { EmailModule } from '../email/email.module';
import { PrivilegeModule } from '../privilege/privilege.module';
import { UploadModule } from '../upload/upload.module'; import { UploadModule } from '../upload/upload.module';
import { UserTokenModule } from '../user-token/user-token.module'; import { UserTokenModule } from '../user-token/user-token.module';
import { userProviders } from './user.providers'; import { userProviders } from './user.providers';
import { UserService } from './user.service'; import { UserService } from './user.service';
@Module({ @Module({
imports: [DatabaseModule, EmailModule, UserTokenModule, UploadModule], imports: [
DatabaseModule,
EmailModule,
UserTokenModule,
UploadModule,
PrivilegeModule,
],
providers: [...userProviders, UserService], providers: [...userProviders, UserService],
exports: [UserService], exports: [UserService],
}) })

View File

@ -10,11 +10,23 @@ block body
.settings__nav-content .settings__nav-content
ul ul
li li
a(href="/account/general", class=path === '/account/general' ? 'active' : '') General a(
href="/account/general",
class=path === '/account/general' ? 'active' : ''
aria-selected=path === '/account/general' ? 'true' : 'false'
) General
li li
a(href="/account/oauth2", class=path === '/account/oauth2' ? 'active' : '') Authorizations a(
href="/account/oauth2",
class=path === '/account/oauth2' ? 'active' : ''
aria-selected=path === '/account/oauth2' ? 'true' : 'false'
) Authorizations
li li
a(href="/account/security", class=path === '/account/security' ? 'active' : '') Security a(
href="/account/security",
class=path === '/account/security' ? 'active' : ''
aria-selected=path === '/account/security' ? 'true' : 'false'
) Security
li li
a(href="/account/logout?csrf=" + csrf) Log out a(href="/account/logout?csrf=" + csrf) Log out
section.content.settings__content section.content.settings__content