Shared services
Some checks failed
FarmMaps.Develop/FarmMapsLib/pipeline/head There was a failure building this commit

This commit is contained in:
2026-02-23 15:22:32 +01:00
parent 5e84eb4404
commit 18092fcc24
8 changed files with 194 additions and 5 deletions

View File

@@ -38,7 +38,10 @@ import { PackageService } from './services/package.service';
import { PackagePreloadStrategy } from './services/package-preload-strategy.service'; import { PackagePreloadStrategy } from './services/package-preload-strategy.service';
import { SenmlService } from './services/senml-service'; import { SenmlService } from './services/senml-service';
import { DeviceService } from './services/device.service'; import { DeviceService } from './services/device.service';
import { GradientService} from './services/gradient.service'; import { GradientService } from './services/gradient.service';
import { UserDataService } from './services/user-data.service';
import { CacheService } from './services/cache-service';
import { SharedItemService } from './services/shared-item.service';
export { export {
FolderService, FolderService,
@@ -69,7 +72,10 @@ export {
SenmlService, SenmlService,
PackagePreloadStrategy, PackagePreloadStrategy,
DeviceService, DeviceService,
GradientService GradientService,
UserDataService,
CacheService,
SharedItemService
}; };
@NgModule({ @NgModule({
@@ -90,9 +96,9 @@ export class AppCommonServiceModule {
providers: [ providers: [
AppConfig, AppConfig,
ItemTypeService, ItemTypeService,
provideAppInitializer(() => { provideAppInitializer(() => {
const initializerFn = (appConfigFactory)(inject(Injector), inject(AppConfig), inject(OAuthService), inject(AuthConfigFactory), inject(OAuthStorage), inject(ItemTypeService)); const initializerFn = (appConfigFactory)(inject(Injector), inject(AppConfig), inject(OAuthService), inject(AuthConfigFactory), inject(OAuthStorage), inject(ItemTypeService));
return initializerFn(); return initializerFn();
}), }),
{ {
provide: HTTP_INTERCEPTORS, provide: HTTP_INTERCEPTORS,

View File

@@ -61,6 +61,9 @@ import { IItemTask, ItemTask } from './models/itemTask';
import { IJsonline } from './models/json-line'; import { IJsonline } from './models/json-line';
import { IListItem } from './models/list.item'; import { IListItem } from './models/list.item';
import { IPackage, IPackages } from './models/package'; import { IPackage, IPackages } from './models/package';
import { IAclRights } from './models/acl.rights';
import { IListItemAclRights } from './models/list.item.acl.rights';
import { ISharedItem } from './models/shared.item';
import { IQueryState } from './models/query.state'; import { IQueryState } from './models/query.state';
import { ISenMLItem } from './models/senml-item'; import { ISenMLItem } from './models/senml-item';
import { ITypeaheadItem } from './models/typeahead.item'; import { ITypeaheadItem } from './models/typeahead.item';
@@ -79,6 +82,7 @@ export {
commonReducers, EditImageModalComponent, commonReducers, EditImageModalComponent,
GradientComponent, GradientComponent,
GradientSelectComponent, HasClaimDirective, HasPackageDirective, HasRoleDirective, IAuthconfigFactory, IColor, IDataLayer, IEventMessage, IGradientstop, IItem, IItemLinkType, IItemTask, IItemType, IItemTypes, IJsonline, IListItem, IPackage, GradientSelectComponent, HasClaimDirective, HasPackageDirective, HasRoleDirective, IAuthconfigFactory, IColor, IDataLayer, IEventMessage, IGradientstop, IItem, IItemLinkType, IItemTask, IItemType, IItemTypes, IJsonline, IListItem, IPackage,
IAclRights, IListItemAclRights, ISharedItem,
IPackages, IQueryState, ISenMLItem, Item, ItemLinkComponent, ItemTask, ITypeaheadItem, IUrlType, IUser, MenuBackgroundComponent, NotFoundComponent, IPackages, IQueryState, ISenMLItem, Item, ItemLinkComponent, ItemTask, ITypeaheadItem, IUrlType, IUser, MenuBackgroundComponent, NotFoundComponent,
NotImplementedComponent, PackageExistsDirective, ResumableFileUploadComponent, SafePipe, SecureOAuthStorage, SessionClearedComponent, SidePanelComponent, TagInputComponent, ThumbnailComponent, TimespanComponent, UserMenuComponent, WeatherCurrentObservation NotImplementedComponent, PackageExistsDirective, ResumableFileUploadComponent, SafePipe, SecureOAuthStorage, SessionClearedComponent, SidePanelComponent, TagInputComponent, ThumbnailComponent, TimespanComponent, UserMenuComponent, WeatherCurrentObservation
}; };

View File

@@ -0,0 +1,9 @@
export interface IAclRights {
id?: number,
claim: any,
expires: Date,
rights: number,
owner: any,
deep: boolean
}

View File

@@ -0,0 +1,6 @@
import { IItem } from '@farmmaps/common';
import { IAclRights } from './acl.rights';
export interface IListItemAclRights extends IItem {
aclRights: IAclRights[]
}

View File

@@ -0,0 +1,13 @@
import { IUser } from '@farmmaps/common';
export interface ISharedItem {
code: string,
name: string,
type: string,
sharedToUser: IUser,
rights: Date,
expires: Date,
dataDate: Date,
childItems: ISharedItem[]
}

View File

@@ -0,0 +1,44 @@
import { Injectable } from '@angular/core';
import { IItem, ItemService } from '@farmmaps/common';
import { OAuthService } from 'angular-oauth2-oidc';
import { Observable, ReplaySubject, Subscription, timer } from 'rxjs';
import { catchError, take } from 'rxjs/operators';
const REFRESH_INTERVAL = 15 * 60 * 1000; // 15m
@Injectable({ providedIn: 'root'})
export class CacheService {
private proxyCacheMap: { [key: string]: ReplaySubject<IItem[]> } = {};
private subscriptionMap: { [key: string]: Subscription } = {};
constructor(private itemService: ItemService, public oauthService: OAuthService) {
timer(0, REFRESH_INTERVAL).subscribe(() => {
this.subscriptionMap = {};
})
}
getItemList(itemType: string) : Observable<IItem[]> {
if (!this.proxyCacheMap[itemType]) {
this.proxyCacheMap[itemType] = new ReplaySubject(1);
}
if (this.oauthService.getAccessToken() != null && !this.subscriptionMap[itemType]) {
this.subscriptionMap[itemType] = this.itemService.getItemList(itemType)
.pipe(
catchError(error => {
this.subscriptionMap[itemType].unsubscribe();
this.subscriptionMap[itemType] = null;
throw error;
}),
).subscribe(items => {
this.proxyCacheMap[itemType].next(items);
});
}
return this.proxyCacheMap[itemType].asObservable()
.pipe(
take(1)
);
}
}

View File

@@ -0,0 +1,73 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { AppConfig, IListItem } from '@farmmaps/common';
import { Observable } from 'rxjs';
import { IListItemAclRights } from '../models/list.item.acl.rights';
import { ISharedItem } from '../models/shared.item';
@Injectable({
providedIn: 'root'
})
export class SharedItemService {
constructor(
public httpClient: HttpClient,
public appConfig: AppConfig) {
}
apiEndpoint() {
return this.appConfig.getConfig('apiEndPoint');
}
public getSharedUsersForItem(itemCode: string): Observable<any> {
return this.httpClient.get<any>(`${this.apiEndpoint()}/api/v1/items/${itemCode}/sharedusers`);
}
getSharedItemsWithRightsInfo(userCode: string): Observable<ISharedItem[]> {
return this.httpClient.get<any>(`${this.apiEndpoint()}/api/v1/users/${userCode}/shared`);
}
shareItem(itemCode: string, userCode: string, userRights: string, expireTimespan: string, deep: boolean): Observable<any> {
const body = {
rights: userRights,
expire: expireTimespan,
deep: deep
};
return this.httpClient.post<any>(`${this.apiEndpoint()}/api/v1/items/${itemCode}/share/${userCode}`, body);
}
revokeSharedItem(itemCode: string, userCode: string): Observable<any> {
return this.httpClient.delete<any>(`${this.apiEndpoint()}/api/v1/items/${itemCode}/share/${userCode}`);
}
getSharedItemRights(sharedByMe: boolean): Observable<IListItemAclRights[]> {
let params = new HttpParams();
params = params.append('byMe', sharedByMe);
return this.httpClient.get<any>(`${this.apiEndpoint()}/api/v1/user/rights`, {params: params});
}
getSharedItemsByParent(parentCode: string): Observable<ISharedItem[]> {
return this.httpClient.get<any>(`${this.apiEndpoint()}/api/v1/items/${parentCode}/sharedchildren`);
}
getSharedWithCurrentUser(profile: string): Observable<IListItem[]> {
let params = new HttpParams();
if (profile != null) {
params = params.append('sharedBy', profile);
}
return this.httpClient.get<any>(`${this.apiEndpoint()}/api/v1/items/shared/`, {params: params});
}
// this method does not belong here, belongs in some sort of item service
public copyItem(itemCode: string, newParentCode: string, newUserCode: string): Observable<any> {
const body = {
itemCode: itemCode,
newParentCode: newParentCode,
newUserCode: newUserCode
};
return this.httpClient.post<any>(`${this.apiEndpoint()}/api/v1/items/copy`, body);
}
}

View File

@@ -0,0 +1,34 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { AppConfig, IUser } from '@farmmaps/common';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserDataService {
constructor(
public httpClient: HttpClient,
public appConfig: AppConfig) {
}
ApiEndpoint() {
return this.appConfig.getConfig('apiEndPoint');
}
loadUserNotifications(): Observable<any> {
return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/notifications`);
}
readUserNotification(notificationCode: string): Observable<any> {
return this.httpClient.put<any>(`${this.ApiEndpoint()}/api/v1/notifications/${notificationCode}`, null);
}
deleteUserNotification(notificationCode: string): Observable<any> {
return this.httpClient.delete<any>(`${this.ApiEndpoint()}/api/v1/notifications/${notificationCode}`);
}
getUserConnections(userCode: string, active: boolean): Observable<IUser[]> {
return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/users/${userCode}/connections?active=${active}`);
}
}