diff --git a/codbex-countries/codbex-countries.gen b/codbex-countries/codbex-countries.gen index 51e0a06..1e9c645 100644 --- a/codbex-countries/codbex-countries.gen +++ b/codbex-countries/codbex-countries.gen @@ -1,15 +1,17 @@ { "tablePrefix": "CODBEX_", "brand": "codbex", - "brandUrl": "https://www.codbex.com", - "title": "Country Management Application", - "description": "Managing country data", + "brandUrl": "https://www.codbex.com/", + "title": "Countries Management Module", + "description": "Managing Countries Data", "projectName": "codbex-countries", "workspaceName": "workspace", "filePath": "codbex-countries.model", - "templateId": "template-application-angular-v2/template/template.js", + "templateId": "template-application-angular-java/template/template.js", "fileName": "codbex-countries", "genFolderName": "codbex-countries", + "javaRuntime": true, + "javaGenFolderName": "codbex_countries", "dataSource": "DefaultDB", "perspectives": { "Settings": { @@ -60,6 +62,7 @@ "widgetDropdownControllerUrl": "", "dataTypeJava": "int", "dataTypeTypescript": "number", + "dataTypeJavaClass": "Integer", "inputRule": "" }, { @@ -87,6 +90,7 @@ "widgetDropdownControllerUrl": "", "dataTypeJava": "string", "dataTypeTypescript": "string", + "dataTypeJavaClass": "String", "minLength": 0, "maxLength": 20, "inputRule": "" @@ -116,6 +120,7 @@ "widgetDropdownControllerUrl": "", "dataTypeJava": "string", "dataTypeTypescript": "string", + "dataTypeJavaClass": "String", "minLength": 0, "maxLength": 2, "inputRule": "" @@ -145,6 +150,7 @@ "widgetDropdownControllerUrl": "", "dataTypeJava": "string", "dataTypeTypescript": "string", + "dataTypeJavaClass": "String", "minLength": 0, "maxLength": 3, "inputRule": "" @@ -174,6 +180,7 @@ "widgetDropdownControllerUrl": "", "dataTypeJava": "string", "dataTypeTypescript": "string", + "dataTypeJavaClass": "String", "minLength": 0, "maxLength": 3, "inputRule": "" @@ -204,6 +211,7 @@ "tooltip": "Country", "type": "SETTING", "dataSource": "DefaultDB", + "javaPerspectiveName": "settings", "referencedProjections": [], "primaryKeys": [ "Id" diff --git a/codbex-countries/gen/codbex-countries/api/Settings/CountryController.ts b/codbex-countries/gen/codbex-countries/api/Settings/CountryController.ts deleted file mode 100644 index ec20802..0000000 --- a/codbex-countries/gen/codbex-countries/api/Settings/CountryController.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Controller, Get, Post, Put, Delete, Documentation, request, response } from '@aerokit/sdk/http' -import { HttpUtils } from "@aerokit/sdk/http/utils"; -import { ValidationError } from '@aerokit/sdk/http/errors' -import { ForbiddenError } from '@aerokit/sdk/http/errors' -import { user } from '@aerokit/sdk/security' -import { Options } from '@aerokit/sdk/db' -import { Extensions } from "@aerokit/sdk/extensions" -import { Injected, Inject } from '@aerokit/sdk/component' -import { CountryRepository } from '../../data/Settings/CountryRepository' -import { CountryEntity } from '../../data/Settings/CountryEntity' - -const validationModules = await Extensions.loadExtensionModules('codbex-countries-Settings-Country', ['validate']); - -@Controller -@Documentation('codbex-countries - Country Controller') -@Injected() -class CountryController { - - @Inject('CountryRepository') - private readonly repository!: CountryRepository; - - @Get('/') - @Documentation('Get All Country') - public getAll(_: any, ctx: any): CountryEntity[] { - try { - this.checkPermissions('read'); - const options: Options = { - limit: ctx.queryParameters["$limit"] ? parseInt(ctx.queryParameters["$limit"]) : 20, - offset: ctx.queryParameters["$offset"] ? parseInt(ctx.queryParameters["$offset"]) : 0, - language: request.getLocale()?.split("_")[0] - }; - - return this.repository.findAll(options); - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Post('/') - @Documentation('Create Country') - public create(entity: CountryEntity): CountryEntity { - try { - this.checkPermissions('write'); - this.validateEntity(entity); - entity.Id = this.repository.create(entity) as any; - response.setHeader('Content-Location', '/services/ts/codbex-countries/gen/codbex-countries/api/Settings/CountryController.ts/' + entity.Id); - response.setStatus(response.CREATED); - return entity; - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Get('/count') - @Documentation('Count Country') - public count(): { count: number } { - try { - this.checkPermissions('read'); - return { count: this.repository.count() }; - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Post('/count') - @Documentation('Count Country with filter') - public countWithFilter(filter: any): { count: number } { - try { - this.checkPermissions('read'); - return { count: this.repository.count(filter) }; - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Post('/search') - @Documentation('Search Country') - public search(filter: any): CountryEntity[] { - try { - this.checkPermissions('read'); - return this.repository.findAll(filter); - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Get('/:id') - @Documentation('Get Country by id') - public getById(_: any, ctx: any): CountryEntity { - try { - this.checkPermissions('read'); - const id = parseInt(ctx.pathParameters.id); - const options: Options = { - language: request.getLocale()?.split("_")[0] - }; - const entity = this.repository.findById(id, options); - if (entity) { - return entity; - } else { - HttpUtils.sendResponseNotFound('Country not found'); - } - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Put('/:id') - @Documentation('Update Country by id') - public update(entity: CountryEntity, ctx: any): CountryEntity { - try { - this.checkPermissions('write'); - const id = parseInt(ctx.pathParameters.id); - entity.Id = id; - this.validateEntity(entity); - this.repository.update(entity); - return entity; - } catch (error: any) { - this.handleError(error); - } - return undefined as any; - } - - @Delete('/:id') - @Documentation('Delete Country by id') - public deleteById(_: any, ctx: any): void { - try { - this.checkPermissions('write'); - const id = parseInt(ctx.pathParameters.id); - const entity = this.repository.findById(id); - if (entity) { - this.repository.deleteById(id); - HttpUtils.sendResponseNoContent(); - } else { - HttpUtils.sendResponseNotFound('Country not found'); - } - } catch (error: any) { - this.handleError(error); - } - } - - private handleError(error: any) { - if (error.name === 'ForbiddenError') { - HttpUtils.sendForbiddenRequest(error.message); - } else if (error.name === 'ValidationError') { - HttpUtils.sendResponseBadRequest(error.message); - } else { - HttpUtils.sendInternalServerError(error.message); - } - } - - private checkPermissions(operationType: string) { - if (operationType === 'read' && !(user.isInRole('codbex-countries.Countries.CountryReadOnly') || user.isInRole('codbex-countries.Countries.CountryFullAccess'))) { - throw new ForbiddenError(); - } - if (operationType === 'write' && !user.isInRole('codbex-countries.Countries.CountryFullAccess')) { - throw new ForbiddenError(); - } - } - - private validateEntity(entity: any): void { - if (entity.Name?.length > 255) { - throw new ValidationError(`The 'Name' exceeds the maximum length of [255] characters`); - } - if (entity.Code2?.length > 2) { - throw new ValidationError(`The 'Code2' exceeds the maximum length of [2] characters`); - } - if (entity.Code3?.length > 3) { - throw new ValidationError(`The 'Code3' exceeds the maximum length of [3] characters`); - } - if (entity.Numeric?.length > 3) { - throw new ValidationError(`The 'Numeric' exceeds the maximum length of [3] characters`); - } - for (const next of validationModules) { - next.validate(entity); - } - } - -} diff --git a/codbex-countries/gen/codbex-countries/data/Settings/CountryEntity.ts b/codbex-countries/gen/codbex-countries/data/Settings/CountryEntity.ts deleted file mode 100644 index 1db7ccf..0000000 --- a/codbex-countries/gen/codbex-countries/data/Settings/CountryEntity.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Entity, Table, Id, Generated, Column, Documentation, CreatedAt, CreatedBy, UpdatedAt, UpdatedBy} from '@aerokit/sdk/db' - -@Entity('CountryEntity') -@Table('CODBEX_COUNTRY') -@Documentation('Country entity mapping') -export class CountryEntity { - - @Id() - @Generated('sequence') - @Documentation('Id') - @Column({ - name: 'COUNTRY_ID', - type: 'integer', - }) - public Id?: number; - - @Documentation('Name') - @Column({ - name: 'COUNTRY_NAME', - type: 'string', - length: 255, - }) - public Name!: string; - - @Documentation('Code2') - @Column({ - name: 'COUNTRY_CODE2', - type: 'string', - length: 2, - }) - public Code2!: string; - - @Documentation('Code3') - @Column({ - name: 'COUNTRY_CODE3', - type: 'string', - length: 3, - }) - public Code3!: string; - - @Documentation('Numeric') - @Column({ - name: 'COUNTRY_NUMERIC', - type: 'string', - length: 3, - }) - public Numeric!: string; - -} - -(new CountryEntity()); diff --git a/codbex-countries/gen/codbex-countries/data/Settings/CountryRepository.ts b/codbex-countries/gen/codbex-countries/data/Settings/CountryRepository.ts deleted file mode 100644 index a818859..0000000 --- a/codbex-countries/gen/codbex-countries/data/Settings/CountryRepository.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Repository, EntityEvent, EntityConstructor, Options } from '@aerokit/sdk/db' -import { Component } from '@aerokit/sdk/component' -import { Producer } from '@aerokit/sdk/messaging' -import { Extensions } from '@aerokit/sdk/extensions' -import { CountryEntity } from './CountryEntity' - -@Component('CountryRepository') -export class CountryRepository extends Repository { - - constructor() { - super((CountryEntity as EntityConstructor)); - } - - protected override async triggerEvent(data: EntityEvent): Promise { - const triggerExtensions = await Extensions.loadExtensionModules('codbex-countries-Settings-Country', ['trigger']); - triggerExtensions.forEach(triggerExtension => { - try { - triggerExtension.trigger(data); - } catch (error) { - console.error(error); - } - }); - Producer.topic('codbex-countries-Settings-Country').send(JSON.stringify(data)); - } -} diff --git a/codbex-countries/gen/codbex-countries/odata/codbex-countries.odata b/codbex-countries/gen/codbex-countries/odata/codbex-countries.odata deleted file mode 100644 index f149140..0000000 --- a/codbex-countries/gen/codbex-countries/odata/codbex-countries.odata +++ /dev/null @@ -1,4 +0,0 @@ -{ - "namespace": "", - "entities": [] -} diff --git a/codbex-countries/gen/codbex-countries/ui/Settings/Country/controller.js b/codbex-countries/gen/codbex-countries/ui/Settings/Country/controller.js index 49abd98..1169c3f 100644 --- a/codbex-countries/gen/codbex-countries/ui/Settings/Country/controller.js +++ b/codbex-countries/gen/codbex-countries/ui/Settings/Country/controller.js @@ -1,6 +1,6 @@ angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) .config(['EntityServiceProvider', (EntityServiceProvider) => { - EntityServiceProvider.baseUrl = '/services/ts/codbex-countries/gen/codbex-countries/api/Settings/CountryController.ts'; + EntityServiceProvider.baseUrl = '/services/java/codbex-countries/gen/codbex_countries/api/settings/CountryController'; }]) .controller('PageController', ($scope, EntityService, Extensions, LocaleService, ButtonStates) => { const Dialogs = new DialogHub(); diff --git a/codbex-countries/gen/codbex-countries/ui/Settings/Country/dialog-window/controller.js b/codbex-countries/gen/codbex-countries/ui/Settings/Country/dialog-window/controller.js index 00774f6..30df8a2 100644 --- a/codbex-countries/gen/codbex-countries/ui/Settings/Country/dialog-window/controller.js +++ b/codbex-countries/gen/codbex-countries/ui/Settings/Country/dialog-window/controller.js @@ -1,6 +1,6 @@ angular.module('page', ['blimpKit', 'platformView', 'platformLocale', 'EntityService']) .config(['EntityServiceProvider', (EntityServiceProvider) => { - EntityServiceProvider.baseUrl = '/services/ts/codbex-countries/gen/codbex-countries/api/Settings/CountryController.ts'; + EntityServiceProvider.baseUrl = '/services/java/codbex-countries/gen/codbex_countries/api/settings/CountryController'; }]) .controller('PageController', ($scope, $http, ViewParameters, LocaleService, EntityService) => { const Dialogs = new DialogHub(); diff --git a/codbex-countries/gen/codbex_countries/api/settings/CountryController.java b/codbex-countries/gen/codbex_countries/api/settings/CountryController.java new file mode 100644 index 0000000..fd9731c --- /dev/null +++ b/codbex-countries/gen/codbex_countries/api/settings/CountryController.java @@ -0,0 +1,176 @@ +package gen.codbex_countries.api.settings; + +import gen.codbex_countries.data.settings.CountryEntity; +import gen.codbex_countries.data.settings.CountryRepository; + +import org.eclipse.dirigible.components.api.security.UserFacade; +import org.eclipse.dirigible.sdk.platform.Documentation; +import org.eclipse.dirigible.sdk.component.Inject; +import org.eclipse.dirigible.sdk.http.Body; +import org.eclipse.dirigible.sdk.http.Controller; +import org.eclipse.dirigible.sdk.http.Delete; +import org.eclipse.dirigible.sdk.http.Get; +import org.eclipse.dirigible.sdk.http.PathParam; +import org.eclipse.dirigible.sdk.http.Post; +import org.eclipse.dirigible.sdk.http.Put; +import org.eclipse.dirigible.sdk.http.QueryParam; +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +@Controller +@Documentation("codbex-countries - Country Controller") +public class CountryController { + + private static final Set FILTER_FIELDS = Set.of("Id", "Name", "Code2", "Code3", "Numeric"); + + @Inject + private CountryRepository repository; + + @Get + @Documentation("List Country") + public List getAll(@QueryParam("$limit") Integer limit, + @QueryParam("$offset") Integer offset) { + checkPermissions("read"); + int actualLimit = limit != null ? limit.intValue() : 20; + int actualOffset = offset != null ? offset.intValue() : 0; + List result = repository.findAll(actualLimit, actualOffset); + return result; + } + + @Get("/count") + @Documentation("Count Country") + public Map count() { + checkPermissions("read"); + return Map.of("count", repository.count()); + } + + @Post("/count") + @Documentation("Count Country with filter") + public Map countWithFilter(@Body Map filter) { + checkPermissions("read"); + return Map.of("count", (long) runFilter(filter).size()); + } + + @Post("/search") + @Documentation("Search Country") + public List search(@Body Map filter) { + checkPermissions("read"); + List result = runFilter(filter); + return result; + } + + @Get("/{id}") + @Documentation("Get Country by id") + public CountryEntity getById(@PathParam("id") Integer id) { + checkPermissions("read"); + CountryEntity entity = repository.findOne(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Country not found")); + return entity; + } + + @Post + @Documentation("Create Country") + public CountryEntity create(@Body CountryEntity entity) { + checkPermissions("write"); + validate(entity); + return repository.save(entity); + } + + @Put("/{id}") + @Documentation("Update Country by id") + public CountryEntity update(@PathParam("id") Integer id, @Body CountryEntity entity) { + checkPermissions("write"); + entity.Id = id; + validate(entity); + return repository.update(entity); + } + + @Delete("/{id}") + @Documentation("Delete Country by id") + public void deleteById(@PathParam("id") Integer id) { + checkPermissions("write"); + if (repository.findOne(id).isEmpty()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Country not found"); + } + repository.deleteById(id); + } + + private List runFilter(Map filter) { + StringBuilder hql = new StringBuilder("from CountryEntity e"); + Map params = new LinkedHashMap<>(); + boolean first = true; + if (filter != null && filter.get("equals") instanceof Map equals) { + for (Map.Entry entry : equals.entrySet()) { + String field = requireKnownField(String.valueOf(entry.getKey())); + String paramName = "p" + params.size(); + hql.append(first ? " where e." : " and e.").append(field).append(" = :").append(paramName); + params.put(paramName, entry.getValue()); + first = false; + } + } + if (filter != null && filter.get("conditions") instanceof List conditions) { + for (Object raw : conditions) { + if (!(raw instanceof Map condition)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid filter condition"); + } + String field = requireKnownField(String.valueOf(condition.get("propertyName"))); + String operator = String.valueOf(condition.get("operator")).toUpperCase(Locale.ROOT); + Object value = condition.get("value"); + String paramName = "p" + params.size(); + String clause = switch (operator) { + case "EQ" -> "e." + field + " = :" + paramName; + case "IN" -> { + if (!(value instanceof Collection)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "IN value must be a list for field: " + field); + } + yield "e." + field + " in (:" + paramName + ")"; + } + case "LIKE" -> "e." + field + " like :" + paramName; + default -> throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported operator: " + operator); + }; + hql.append(first ? " where " : " and ").append(clause); + params.put(paramName, value); + first = false; + } + } + return repository.query(hql.toString(), params); + } + + private static String requireKnownField(String field) { + if (!FILTER_FIELDS.contains(field)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unknown filter field: " + field); + } + return field; + } + + private void checkPermissions(String op) { + if ("read".equals(op) && !(UserFacade.isInRole("codbex-countries.Countries.CountryReadOnly") || UserFacade.isInRole("codbex-countries.Countries.CountryFullAccess"))) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + if ("write".equals(op) && !UserFacade.isInRole("codbex-countries.Countries.CountryFullAccess")) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + } + + private static void validate(CountryEntity entity) { + if (entity.Name != null && entity.Name.length() > 255) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The 'Name' exceeds the maximum length of 255"); + } + if (entity.Code2 != null && entity.Code2.length() > 2) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The 'Code2' exceeds the maximum length of 2"); + } + if (entity.Code3 != null && entity.Code3.length() > 3) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The 'Code3' exceeds the maximum length of 3"); + } + if (entity.Numeric != null && entity.Numeric.length() > 3) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The 'Numeric' exceeds the maximum length of 3"); + } + } +} diff --git a/codbex-countries/gen/codbex-countries/data/Settings/Country.extensionpoint b/codbex-countries/gen/codbex_countries/data/settings/Country.extensionpoint similarity index 98% rename from codbex-countries/gen/codbex-countries/data/Settings/Country.extensionpoint rename to codbex-countries/gen/codbex_countries/data/settings/Country.extensionpoint index 97b4ad0..4590078 100644 --- a/codbex-countries/gen/codbex-countries/data/Settings/Country.extensionpoint +++ b/codbex-countries/gen/codbex_countries/data/settings/Country.extensionpoint @@ -1,4 +1,4 @@ { "name": "codbex-countries-Settings-Country", "description": "Extension Point for the codbex-countries-Settings-Country entity" -} \ No newline at end of file +} diff --git a/codbex-countries/gen/codbex_countries/data/settings/CountryEntity.java b/codbex-countries/gen/codbex_countries/data/settings/CountryEntity.java new file mode 100644 index 0000000..e16608e --- /dev/null +++ b/codbex-countries/gen/codbex_countries/data/settings/CountryEntity.java @@ -0,0 +1,42 @@ +package gen.codbex_countries.data.settings; + +import org.eclipse.dirigible.sdk.db.Column; +import org.eclipse.dirigible.sdk.db.CreatedAt; +import org.eclipse.dirigible.sdk.db.CreatedBy; +import org.eclipse.dirigible.sdk.platform.Documentation; +import org.eclipse.dirigible.sdk.db.Entity; +import org.eclipse.dirigible.sdk.db.GeneratedValue; +import org.eclipse.dirigible.sdk.db.GenerationType; +import org.eclipse.dirigible.sdk.db.Id; +import org.eclipse.dirigible.sdk.db.Table; +import org.eclipse.dirigible.sdk.db.UpdatedAt; +import org.eclipse.dirigible.sdk.db.UpdatedBy; + +@Entity +@Table(name = "CODBEX_COUNTRY") +@Documentation("Country entity mapping") +public class CountryEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "COUNTRY_ID") + @Documentation("Id") + public Integer Id; + + @Column(name = "COUNTRY_NAME", length = 255, nullable = false, unique = true) + @Documentation("Name") + public String Name; + + @Column(name = "COUNTRY_CODE2", length = 2, nullable = false, unique = true) + @Documentation("Code2") + public String Code2; + + @Column(name = "COUNTRY_CODE3", length = 3, nullable = false, unique = true) + @Documentation("Code3") + public String Code3; + + @Column(name = "COUNTRY_NUMERIC", length = 3, nullable = false, unique = true) + @Documentation("Numeric") + public String Numeric; + +} diff --git a/codbex-countries/gen/codbex_countries/data/settings/CountryRepository.java b/codbex-countries/gen/codbex_countries/data/settings/CountryRepository.java new file mode 100644 index 0000000..8a36c35 --- /dev/null +++ b/codbex-countries/gen/codbex_countries/data/settings/CountryRepository.java @@ -0,0 +1,12 @@ +package gen.codbex_countries.data.settings; + +import org.eclipse.dirigible.components.data.store.java.repository.JavaRepository; +import org.eclipse.dirigible.sdk.component.Repository; + +@Repository +public class CountryRepository extends JavaRepository { + + public CountryRepository() { + super(CountryEntity.class); + } +} diff --git a/codbex-countries/gen/codbex-countries/roles/default-roles.roles b/codbex-countries/gen/codbex_countries/roles/default-roles.roles similarity index 99% rename from codbex-countries/gen/codbex-countries/roles/default-roles.roles rename to codbex-countries/gen/codbex_countries/roles/default-roles.roles index e2b4a60..a206552 100644 --- a/codbex-countries/gen/codbex-countries/roles/default-roles.roles +++ b/codbex-countries/gen/codbex_countries/roles/default-roles.roles @@ -7,4 +7,4 @@ "name": "codbex-countries.Countries.CountryFullAccess", "description": "A role that grants full access for Country." } -] \ No newline at end of file +]