Skip to content

Repository files navigation

AppAbilityPackage

Installation

# if you use npm
npm install @xbisa/appabilitypackage

Usage in frontend

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>
 }
}

Usage in backend API

@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' };
 }

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages