Add icon component, update logo handling, and enhance user profile display
This commit is contained in:
parent
d0fd155ea3
commit
6db373573c
@ -18,7 +18,7 @@
|
|||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular-devkit/build-angular:application",
|
"builder": "@angular/build:application",
|
||||||
"options": {
|
"options": {
|
||||||
"outputPath": "dist/frontend",
|
"outputPath": "dist/frontend",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
@ -64,7 +64,7 @@
|
|||||||
"defaultConfiguration": "production"
|
"defaultConfiguration": "production"
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular-devkit/build-angular:dev-server",
|
"builder": "@angular/build:dev-server",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"buildTarget": "frontend:build:production"
|
"buildTarget": "frontend:build:production"
|
||||||
@ -79,10 +79,10 @@
|
|||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
},
|
},
|
||||||
"extract-i18n": {
|
"extract-i18n": {
|
||||||
"builder": "@angular-devkit/build-angular:extract-i18n"
|
"builder": "@angular/build:extract-i18n"
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular/build:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"polyfills": [
|
"polyfills": [
|
||||||
"zone.js",
|
"zone.js",
|
||||||
@ -104,5 +104,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"type": "component"
|
||||||
|
},
|
||||||
|
"@schematics/angular:directive": {
|
||||||
|
"type": "directive"
|
||||||
|
},
|
||||||
|
"@schematics/angular:service": {
|
||||||
|
"type": "service"
|
||||||
|
},
|
||||||
|
"@schematics/angular:guard": {
|
||||||
|
"typeSeparator": "."
|
||||||
|
},
|
||||||
|
"@schematics/angular:interceptor": {
|
||||||
|
"typeSeparator": "."
|
||||||
|
},
|
||||||
|
"@schematics/angular:module": {
|
||||||
|
"typeSeparator": "."
|
||||||
|
},
|
||||||
|
"@schematics/angular:pipe": {
|
||||||
|
"typeSeparator": "."
|
||||||
|
},
|
||||||
|
"@schematics/angular:resolver": {
|
||||||
|
"typeSeparator": "."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,24 +10,24 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^19.1.0",
|
"@angular/animations": "^20.3.6",
|
||||||
"@angular/common": "^19.1.0",
|
"@angular/common": "^20.3.6",
|
||||||
"@angular/compiler": "^19.1.0",
|
"@angular/compiler": "^20.3.6",
|
||||||
"@angular/core": "^19.1.0",
|
"@angular/core": "^20.3.6",
|
||||||
"@angular/forms": "^19.1.0",
|
"@angular/forms": "^20.3.6",
|
||||||
"@angular/platform-browser": "^19.1.0",
|
"@angular/platform-browser": "^20.3.6",
|
||||||
"@angular/platform-browser-dynamic": "^19.1.0",
|
"@angular/platform-browser-dynamic": "^20.3.6",
|
||||||
"@angular/platform-server": "^19.1.0",
|
"@angular/platform-server": "^20.3.6",
|
||||||
"@angular/router": "^19.1.0",
|
"@angular/router": "^20.3.6",
|
||||||
"@angular/ssr": "^19.2.14",
|
"@angular/ssr": "^20.3.6",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.15.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^19.1.7",
|
"@angular/build": "^20.3.6",
|
||||||
"@angular/cli": "^19.1.7",
|
"@angular/cli": "^20.3.6",
|
||||||
"@angular/compiler-cli": "^19.1.0",
|
"@angular/compiler-cli": "^20.3.6",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"@types/node": "^18.18.0",
|
"@types/node": "^18.18.0",
|
||||||
"jasmine-core": "~5.5.0",
|
"jasmine-core": "~5.5.0",
|
||||||
@ -36,6 +36,6 @@
|
|||||||
"karma-coverage": "~2.2.0",
|
"karma-coverage": "~2.2.0",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"typescript": "~5.7.2"
|
"typescript": "~5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
5618
src/angular/frontend/pnpm-lock.yaml
generated
5618
src/angular/frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
src/angular/frontend/public/full_logo.svg
(Stored with Git LFS)
BIN
src/angular/frontend/public/full_logo.svg
(Stored with Git LFS)
Binary file not shown.
@ -3,6 +3,7 @@ import {LoginComponent} from './components/login/login.component';
|
|||||||
import {HomeComponent} from './components/home/home.component';
|
import {HomeComponent} from './components/home/home.component';
|
||||||
import {authGuard} from './guards/auth.guard';
|
import {authGuard} from './guards/auth.guard';
|
||||||
import {ShellComponent} from './components/shell/shell.component';
|
import {ShellComponent} from './components/shell/shell.component';
|
||||||
|
import {subjectResolver} from './resolvers/subject.resolver';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -21,6 +22,9 @@ export const routes: Routes = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
canActivate: [authGuard],
|
canActivate: [authGuard],
|
||||||
|
resolve: {
|
||||||
|
user: subjectResolver,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '**',
|
path: '**',
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {GandalfClient} from '../gandalf-client';
|
import {GandalfClient} from '../gandalf-client';
|
||||||
import {lastValueFrom, Observable, ObservableInput} from 'rxjs';
|
import {lastValueFrom, Observable} from 'rxjs';
|
||||||
|
|
||||||
export interface ValidateCredentialsCommand {
|
export interface ValidateCredentialsCommand {
|
||||||
usernameOrEmail: string;
|
usernameOrEmail: string;
|
||||||
@ -31,4 +31,13 @@ export class AuthService extends GandalfClient {
|
|||||||
return lastValueFrom(this.login$(command, onError));
|
return lastValueFrom(this.login$(command, onError));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logout$(onError?: (error: any) => void): Observable<void> {
|
||||||
|
return this.handleRequest(this.http.get<void>(this.base + '/logout'), onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
logoutAsync(onError?: (error: any) => void): Promise<void> {
|
||||||
|
return lastValueFrom(this.logout$(onError));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {GandalfClient} from "../gandalf-client";
|
||||||
|
import {lastValueFrom, Observable} from "rxjs";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ProxyService extends GandalfClient {
|
||||||
|
|
||||||
|
private base = '/api/appproxy/q5lBLamL6rKy';
|
||||||
|
|
||||||
|
me$(onError?: (error: any) => void): Observable<{ "name": string }> {
|
||||||
|
return this.handleRequest(this.http.get<{ "name": string }>(this.base + '/api/subject/me'), onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
meAsync(onError?: (error: any) => void): Promise<{ "name": string }> {
|
||||||
|
return lastValueFrom(this.me$(onError));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
@if (path()) {
|
||||||
|
<div class="icon masked" style='--mask-path: url("{{path()}}")'></div>
|
||||||
|
} @else {
|
||||||
|
<div class="icon"></div>
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
.icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
&.masked {
|
||||||
|
mask: var(--mask-path) no-repeat;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-position: center;
|
||||||
|
background-color: var(--text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { IconComponent } from './icon.component';
|
||||||
|
|
||||||
|
describe('IconComponent', () => {
|
||||||
|
let component: IconComponent;
|
||||||
|
let fixture: ComponentFixture<IconComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [IconComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(IconComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import {Component, input} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-icon',
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './icon.component.html',
|
||||||
|
styleUrl: './icon.component.scss'
|
||||||
|
})
|
||||||
|
export class IconComponent {
|
||||||
|
public path = input<string>('');
|
||||||
|
}
|
||||||
@ -1 +1,5 @@
|
|||||||
<p>nav-profile works!</p>
|
<div class="user-info">
|
||||||
|
<span>{{user()}}</span>
|
||||||
|
<a href="" (click)="logout($event)">Logout</a>
|
||||||
|
</div>
|
||||||
|
<div class="profile-picture neutral-30"></div>
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
a {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-picture {
|
||||||
|
margin-left: 1rem;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,7 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, computed, inject} from '@angular/core';
|
||||||
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
|
import {toSignal} from '@angular/core/rxjs-interop';
|
||||||
|
import {AuthService} from '../../../clients/gandalf/mithrandir/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-nav-profile',
|
selector: 'app-nav-profile',
|
||||||
@ -8,5 +11,17 @@ import { Component } from '@angular/core';
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
})
|
})
|
||||||
export class NavProfileComponent {
|
export class NavProfileComponent {
|
||||||
|
private route = inject(ActivatedRoute);
|
||||||
|
private authService = inject(AuthService); // Replace 'any' with the actual type of AuthService
|
||||||
|
private router = inject(Router); // Replace 'any' with the actual type of AuthService
|
||||||
|
private data = toSignal(this.route.data);
|
||||||
|
|
||||||
|
|
||||||
|
user = computed(() => this.data()?.["user"] as string | undefined ?? 'Unknown');
|
||||||
|
|
||||||
|
async logout($event: PointerEvent) {
|
||||||
|
$event.preventDefault();
|
||||||
|
await this.authService.logoutAsync();
|
||||||
|
await this.router.navigate(['/login']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<app-panel class="shell-nav-bar primary-50">
|
<app-panel class="shell-nav-bar neutral-20">
|
||||||
<img class="logo" src="/full_logo.svg" alt="logo">
|
<app-icon path="/full_logo.svg" class="logo primary-icon-50"></app-icon>
|
||||||
<app-nav-profile></app-nav-profile>
|
<app-nav-profile></app-nav-profile>
|
||||||
</app-panel>
|
</app-panel>
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
.shell-nav-bar {
|
.shell-nav-bar {
|
||||||
.logo {
|
.logo {
|
||||||
height: 3rem;
|
$height: 3rem;
|
||||||
|
height: $height;
|
||||||
|
width: #{$height * 3.356876171875};
|
||||||
}
|
}
|
||||||
app-nav-profile {
|
app-nav-profile {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, computed, inject} from '@angular/core';
|
||||||
import {NavProfileComponent} from './nav-profile/nav-profile.component';
|
import {NavProfileComponent} from './nav-profile/nav-profile.component';
|
||||||
import {RouterOutlet} from '@angular/router';
|
import {ActivatedRoute, RouterOutlet} from '@angular/router';
|
||||||
import {PanelComponent} from '../panel/panel.component';
|
import {PanelComponent} from '../panel/panel.component';
|
||||||
|
import {IconComponent} from '../icon/icon.component';
|
||||||
|
import {toSignal} from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-shell',
|
selector: 'app-shell',
|
||||||
imports: [
|
imports: [
|
||||||
NavProfileComponent,
|
NavProfileComponent,
|
||||||
RouterOutlet,
|
PanelComponent,
|
||||||
PanelComponent
|
IconComponent
|
||||||
],
|
],
|
||||||
templateUrl: './shell.component.html',
|
templateUrl: './shell.component.html',
|
||||||
styleUrl: './shell.component.scss',
|
styleUrl: './shell.component.scss',
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { ResolveFn } from '@angular/router';
|
||||||
|
|
||||||
|
import { subjectResolver } from './subject.resolver';
|
||||||
|
|
||||||
|
describe('subjectResolver', () => {
|
||||||
|
const executeResolver: ResolveFn<boolean> = (...resolverParameters) =>
|
||||||
|
TestBed.runInInjectionContext(() => subjectResolver(...resolverParameters));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(executeResolver).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
15
src/angular/frontend/src/app/resolvers/subject.resolver.ts
Normal file
15
src/angular/frontend/src/app/resolvers/subject.resolver.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import {ResolveFn} from '@angular/router';
|
||||||
|
import {inject} from '@angular/core';
|
||||||
|
import {ProxyService} from '../clients/gandalf/mithrandir/proxy.service';
|
||||||
|
import {map} from 'rxjs';
|
||||||
|
|
||||||
|
export const subjectResolver: ResolveFn<string> = (route, state) => {
|
||||||
|
const proxyService = inject(ProxyService);
|
||||||
|
return proxyService.me$().pipe(
|
||||||
|
map(x => {
|
||||||
|
console.log(x);
|
||||||
|
return x.name;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -14,12 +14,6 @@ $danger-color: hsl(10, 80%, 50%);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin set-neutral-colors($step: 10) {
|
|
||||||
@for $i from 0 through 100/$step {
|
|
||||||
--neutral-#{$i * $step}: hsl(0, 0%, #{$i * $step}%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin set-common-colors() {
|
@mixin set-common-colors() {
|
||||||
--primary-color: #{$primary-color};
|
--primary-color: #{$primary-color};
|
||||||
--secondary-color: #{$secondary-color};
|
--secondary-color: #{$secondary-color};
|
||||||
@ -29,21 +23,39 @@ $danger-color: hsl(10, 80%, 50%);
|
|||||||
--danger-color: #{$danger-color};
|
--danger-color: #{$danger-color};
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin set-color-classes($name, $color, $step: 10, $padded: false) {
|
@mixin set-color-classes($name, $color, $step: 10, $padded: false, $text-color-swap-step: 30, $text-color-swap-light: var(--neutral-10), $text-color-swap-dark: var(--neutral-90)) {
|
||||||
$from: if($padded, 0, 1);
|
$from: 1;
|
||||||
$to: if($padded, 100/$step, (100/$step)-1);
|
$to: 100/$step;
|
||||||
|
|
||||||
|
@if $padded {
|
||||||
|
$from: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if not $padded {
|
||||||
|
$to: $to - 1;
|
||||||
|
}
|
||||||
|
|
||||||
@for $i from $from through $to {
|
@for $i from $from through $to {
|
||||||
.#{$name}-#{$i * $step} {
|
.#{$name}-#{$i * $step} {
|
||||||
--bg-color: hsl(#{color.hue($color)}, #{color.saturation($color)}, #{$i * $step}%);
|
--bg-color: hsl(#{color.hue($color)}, #{color.saturation($color)}, #{$i * $step}%);
|
||||||
--text-color: var(--neutral-10);
|
|
||||||
|
@if $i * $step <= $text-color-swap-step {
|
||||||
|
--text-color: #{$text-color-swap-dark};
|
||||||
|
} @else {
|
||||||
|
--text-color: #{$text-color-swap-light};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from $from through $to {
|
||||||
|
.#{$name}-icon-#{$i * $step} {
|
||||||
|
--text-color: hsl(#{color.hue($color)}, #{color.saturation($color)}, #{$i * $step}%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@include set-neutral-colors();
|
@include set-color-shades("neutral", hsl(0, 0%, 0%), 10);
|
||||||
@include set-common-colors();
|
@include set-common-colors();
|
||||||
@include set-color-shades("primary", $primary-color, 10);
|
@include set-color-shades("primary", $primary-color, 10);
|
||||||
@include set-color-shades("secondary", $secondary-color, 10);
|
@include set-color-shades("secondary", $secondary-color, 10);
|
||||||
@ -59,8 +71,18 @@ $danger-color: hsl(10, 80%, 50%);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include set-color-classes("primary", $primary-color, 10, true);
|
a {
|
||||||
@include set-color-classes("secondary", $secondary-color, 10);
|
color: var(--secondary-70);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include set-color-classes("neutral", hsl(0, 0%, 0%), 10, true);
|
||||||
|
@include set-color-classes("primary", $primary-color, 10, false);
|
||||||
|
@include set-color-classes("secondary", $secondary-color, 10, false, 60);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,3 @@ body {
|
|||||||
background-color: var(--bg-color);
|
background-color: var(--bg-color);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
#path1 { fill: black; }
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
#path1 { fill: white; }
|
|
||||||
}
|
|
||||||
|
|||||||
@ -110,6 +110,21 @@ public class AuthController : ControllerBase
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("[action]")]
|
||||||
|
public async Task<IActionResult> Me()
|
||||||
|
{
|
||||||
|
var sessionExists = Request.Cookies.ContainsKey("MithrandirSession");
|
||||||
|
|
||||||
|
if (!sessionExists)
|
||||||
|
{
|
||||||
|
return Unauthorized("Session expired.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return Ok(sessionExists);
|
||||||
|
}
|
||||||
|
|
||||||
private string GetCacheKey(string subjectId, string appId, string tokenType)
|
private string GetCacheKey(string subjectId, string appId, string tokenType)
|
||||||
{
|
{
|
||||||
return $"{subjectId}:{appId}:{tokenType}";
|
return $"{subjectId}:{appId}:{tokenType}";
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Suspectus.Gandalf.Palantir.Abstractions;
|
||||||
|
using Suspectus.Gandalf.Palantir.Data.Database;
|
||||||
|
|
||||||
|
namespace Suspectus.Gandalf.Palantir.Api.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class SubjectController(InvokerContext invokerContext, ApplicationContext context) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet("me")]
|
||||||
|
public async Task<IActionResult> GetSubject()
|
||||||
|
{
|
||||||
|
var subject = await context.Subjects.Where(x => x.Id == invokerContext.Invoker!.SubjectId).Select(x => x.Name).SingleAsync();
|
||||||
|
return Ok(new { Name = subject });
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user