# if you use npm
npm install @xbisa/appabilitypackage
import { PureAbility } from '@casl/ability';
import { inject, Injectable } from '@angular/core';
import { Action, defineAbilityFor, Subjects, User } from '@xbisa/appabilitypackage';
import { AccountService } from './account.service';
@Injectable({
providedIn: 'root',
})
export class CaslAbilityFactory {
private accountService = inject(AccountService);
defineAbilityFor(user: User): PureAbility<[Action, Subjects]> {
return defineAbilityFor(this.accountService.authenticated ? user : { ...user, roles: [] });
}
}
import { ChangeDetectionStrategy, Component, computed, inject, signal, Signal, viewChild } from '@angular/core';
import { AccountService } from '../lib/core/account.service';
import { CaslAbilityFactory } from '../lib/core/casl-ability.factory';
import {
User,
UserFields,
Behavior,
BehaviorFields,
ChangeGoals,
ChangeGoalsFields
} from '@xbisa/appabilitypackage';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
@Component({
selector: 'app-header',
standalone: true,
imports: [CommonModule, RouterModule],
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeaderComponent {
User = User;
UserFields = UserFields;
private readonly caslAbilityFactory = inject(CaslAbilityFactory);
private readonly accountService = inject(AccountService);
user = toSignal(this.accountService.currentUser, { initialValue: {} as UserDataModel });
ability = computed(() => this.caslAbilityFactory.defineAbilityFor(this.user()));
}
<ul class='navbar-nav'>
@if (ability().can('create', Behavior, BehaviorFields.BEHAVIOR)) {
<li class='nav-item fs-5'>
<a class='nav-link'
routerLinkActive='active'
[routerLink]="['/behavior']"
[queryParams]='{ desiredBehavior: false }'
queryParamsHandling='merge'
aria-current='page'
title='Registrer Adfærd'
>
Register Behavior
</a>
</li>
}
@if (ability().can('create', ChangeGoals, ChangeGoalsFields.GOAL_DESCRIPTION_CHILD)) {
<li class='nav-item fs-5'>
<a
class='nav-link'
routerLinkActive='active'
[routerLink]="['/change-goals']"
queryParamsHandling='merge'
aria-current='page'
title='Mål for forandring'
>
Change Goals
</a>
</li>
}
@if (ability().can('update', User, UserFields.COACHES)) {
<li class='av-item fs-5'>
<a class='nav-link'
routerLinkActive='active'
[routerLink]="['/users']"
aria-current='page'
title='Tildel coach til forældrebruger'
>
Assign coach to user
</a>
</li>
}
</ul>
@if (control.value | toBehavior; as behavior) {
@if (!behavior.id || (ability.can('update', behavior, BehaviorFields.BEHAVIOR) && ability.can('update', behavior, BehaviorFields.DESCRIPTION))) {
<button
type='button'
class='btn btn-secondary d-flex align-items-center flex-grow-1 flex-xxl-grow-0'
(click)='onEditClick(i)'
title='Rediger'
>
<i class='bi bi-pen me-2 fs-6'></i>
Edit
</button>
}
@if (!behavior.id || ability.can('delete', behavior)) {
<button
class='btn btn-danger text-white d-flex align-items-center flex-grow-1 flex-xxl-grow-0'
type='button'
(click)='onDeleteClick(control.value.id)'
title='Fjern'
>
<i class='bi bi-trash3 me-2 fs-6'></i>
Remove
</button>
}
}
@Delete(':id')
@CheckPolicies((ability: AppAbility, data: BehaviorModel) => {
const behavior = new Behavior();
Object.assign(behavior, data);
return ability.can('delete', behavior);
})
@ApiBearerAuth()
@UseGuards(
JwtAuthGuard,
RolesGuard,
BehaviorGuard(async (req: Request, behaviorsService: BehaviorsService) => {
const behaviorId = req.params['id'];
return (await behaviorsService.getBehaviorModelById(behaviorId)).data;
}),
)
@Roles(UserRole.PARENT)
@ApiParam({
name: 'id',
type: String,
required: true,
})
async deleteBehavior(
@Req() request: Request,
@Param('id') id: string,
): Promise<{ status: string }> {
await this.behaviorsService.deleteBehaviorById(id);
return { status: 'deleted' };
}