code push initiall
This commit is contained in:
parent
73c518e3fa
commit
ef415acd4b
16
angular/.editorconfig
Normal file
16
angular/.editorconfig
Normal file
@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
50
angular/.eslintrc.json
Normal file
50
angular/.eslintrc.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"tsconfig.json"
|
||||
],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
46
angular/.gitignore
vendored
Normal file
46
angular/.gitignore
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.angular/cache
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
5
angular/.prettierrc
Normal file
5
angular/.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"arrowParens": "avoid"
|
||||
}
|
27
angular/README.md
Normal file
27
angular/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# BookStore
|
||||
|
||||
This is a startup project based on the ABP framework. For more information, visit <a href="https://abp.io/" target="_blank">abp.io</a>
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
190
angular/angular.json
Normal file
190
angular/angular.json
Normal file
@ -0,0 +1,190 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"cli": {
|
||||
"analytics": false,
|
||||
"schematicCollections": ["@angular-eslint/schematics"]
|
||||
},
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"BookStore": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/BookStore",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"allowedCommonJsDependencies": ["chart.js", "js-sha256"],
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": [
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css",
|
||||
"inject": false,
|
||||
"bundleName": "bootstrap-dim"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/ng-bundle.css",
|
||||
"inject": false,
|
||||
"bundleName": "ng-bundle"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/side-menu/layout-bundle.css",
|
||||
"inject": false,
|
||||
"bundleName": "layout-bundle"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@abp/ng.theme.lepton-x/assets/css/abp-bundle.css",
|
||||
"inject": false,
|
||||
"bundleName": "abp-bundle"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.rtl.css",
|
||||
"inject": false,
|
||||
"bundleName": "bootstrap-dim.rtl"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/font-bundle.rtl.css",
|
||||
"inject": false,
|
||||
"bundleName": "font-bundle.rtl"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/font-bundle.css",
|
||||
"inject": false,
|
||||
"bundleName": "font-bundle"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/ng-bundle.rtl.css",
|
||||
"inject": false,
|
||||
"bundleName": "ng-bundle.rtl"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/side-menu/layout-bundle.rtl.css",
|
||||
"inject": false,
|
||||
"bundleName": "layout-bundle.rtl"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@abp/ng.theme.lepton-x/assets/css/abp-bundle.rtl.css",
|
||||
"inject": false,
|
||||
"bundleName": "abp-bundle.rtl"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/bootstrap-icons/font/bootstrap-icons.css",
|
||||
"inject": true,
|
||||
"bundleName": "bootstrap-icons"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@fortawesome/fontawesome-free/css/all.min.css",
|
||||
"inject": true,
|
||||
"bundleName": "fontawesome-all.min"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@fortawesome/fontawesome-free/css/v4-shims.min.css",
|
||||
"inject": true,
|
||||
"bundleName": "fontawesome-v4-shims.min"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@swimlane/ngx-datatable/index.css",
|
||||
"inject": true,
|
||||
"bundleName": "ngx-datatable-index"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
|
||||
"inject": true,
|
||||
"bundleName": "ngx-datatable-icons"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
|
||||
"inject": true,
|
||||
"bundleName": "ngx-datatable-material"
|
||||
},
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "2.5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "BookStore:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "BookStore:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "BookStore:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.scss"],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
angular/karma.conf.js
Normal file
44
angular/karma.conf.js
Normal file
@ -0,0 +1,44 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/BookStore'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
62
angular/package.json
Normal file
62
angular/package.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "BookStore",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --open",
|
||||
"build": "ng build",
|
||||
"build:prod": "ng build --configuration production",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@abp/ng.account": "~8.1.3",
|
||||
"@abp/ng.components": "~8.1.3",
|
||||
"@abp/ng.core": "~8.1.3",
|
||||
"@abp/ng.identity": "~8.1.3",
|
||||
"@abp/ng.oauth": "~8.1.3",
|
||||
"@abp/ng.setting-management": "~8.1.3",
|
||||
"@abp/ng.tenant-management": "~8.1.3",
|
||||
"@abp/ng.theme.lepton-x": "~3.1.3",
|
||||
"@abp/ng.theme.shared": "~8.1.3",
|
||||
"@angular/animations": "~17.1.0",
|
||||
"@angular/common": "~17.1.0",
|
||||
"@angular/compiler": "~17.1.0",
|
||||
"@angular/core": "~17.1.0",
|
||||
"@angular/forms": "~17.1.0",
|
||||
"@angular/localize": "~17.1.0",
|
||||
"@angular/platform-browser": "~17.1.0",
|
||||
"@angular/platform-browser-dynamic": "~17.1.0",
|
||||
"@angular/router": "~17.1.0",
|
||||
"bootstrap-icons": "~1.8.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "~0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@abp/ng.schematics": "~8.1.3",
|
||||
"@angular-devkit/build-angular": "~17.1.0",
|
||||
"@angular-eslint/builder": "~17.2.0",
|
||||
"@angular-eslint/eslint-plugin": "~17.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "~17.2.0",
|
||||
"@angular-eslint/schematics": "~17.2.0",
|
||||
"@angular-eslint/template-parser": "~17.2.0",
|
||||
"@angular/cli": "~17.1.0",
|
||||
"@angular/compiler-cli": "~17.1.0",
|
||||
"@angular/language-service": "~17.1.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"@typescript-eslint/eslint-plugin": "6.9.1",
|
||||
"@typescript-eslint/parser": "6.9.1",
|
||||
"eslint": "^8.23.0",
|
||||
"jasmine-core": "~4.0.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.1.0",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.7.0",
|
||||
"typescript": "~5.3.0"
|
||||
}
|
||||
}
|
37
angular/src/app/app-routing.module.ts
Normal file
37
angular/src/app/app-routing.module.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
loadChildren: () => import('./home/home.module').then(m => m.HomeModule),
|
||||
},
|
||||
{
|
||||
path: 'account',
|
||||
loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()),
|
||||
},
|
||||
{
|
||||
path: 'identity',
|
||||
loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
|
||||
},
|
||||
{
|
||||
path: 'tenant-management',
|
||||
loadChildren: () =>
|
||||
import('@abp/ng.tenant-management').then(m => m.TenantManagementModule.forLazy()),
|
||||
},
|
||||
{
|
||||
path: 'setting-management',
|
||||
loadChildren: () =>
|
||||
import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()),
|
||||
},
|
||||
{ path: 'books', loadChildren: () => import('./book/book.module').then(m => m.BookModule) },
|
||||
{ path: 'customer', loadChildren: () => import('./customer/customer.module').then(m => m.CustomerModule) },
|
||||
{ path: 'book-issue', loadChildren: () => import('./book-issue/book-issue.module').then(m => m.BookIssueModule) },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, {})],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
11
angular/src/app/app.component.ts
Normal file
11
angular/src/app/app.component.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<abp-loader-bar></abp-loader-bar>
|
||||
<abp-dynamic-layout></abp-dynamic-layout>
|
||||
<abp-internet-status></abp-internet-status>
|
||||
`,
|
||||
})
|
||||
export class AppComponent {}
|
48
angular/src/app/app.module.ts
Normal file
48
angular/src/app/app.module.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { AccountConfigModule } from '@abp/ng.account/config';
|
||||
import { CoreModule } from '@abp/ng.core';
|
||||
import { registerLocale } from '@abp/ng.core/locale';
|
||||
import { IdentityConfigModule } from '@abp/ng.identity/config';
|
||||
import { SettingManagementConfigModule } from '@abp/ng.setting-management/config';
|
||||
import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config';
|
||||
import { InternetConnectionStatusComponent, ThemeSharedModule } from '@abp/ng.theme.shared';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { environment } from '../environments/environment';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { APP_ROUTE_PROVIDER } from './route.provider';
|
||||
import { FeatureManagementModule } from '@abp/ng.feature-management';
|
||||
import { AbpOAuthModule } from '@abp/ng.oauth';
|
||||
import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
|
||||
import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
|
||||
import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
CoreModule.forRoot({
|
||||
environment,
|
||||
registerLocaleFn: registerLocale(),
|
||||
}),
|
||||
AbpOAuthModule.forRoot(),
|
||||
ThemeSharedModule.forRoot(),
|
||||
|
||||
AccountConfigModule.forRoot(),
|
||||
IdentityConfigModule.forRoot(),
|
||||
TenantManagementConfigModule.forRoot(),
|
||||
SettingManagementConfigModule.forRoot(),
|
||||
|
||||
|
||||
FeatureManagementModule.forRoot(),
|
||||
InternetConnectionStatusComponent,
|
||||
ThemeLeptonXModule.forRoot(),
|
||||
SideMenuLayoutModule.forRoot(),
|
||||
AccountLayoutModule.forRoot()
|
||||
],
|
||||
declarations: [AppComponent],
|
||||
providers: [APP_ROUTE_PROVIDER],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
12
angular/src/app/book-issue/book-issue-routing.module.ts
Normal file
12
angular/src/app/book-issue/book-issue-routing.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { BookIssueComponent } from './book-issue.component';
|
||||
import { authGuard, permissionGuard } from '@abp/ng.core';
|
||||
|
||||
const routes: Routes = [{ path: '', component: BookIssueComponent,canActivate: [authGuard, permissionGuard] }];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class BookIssueRoutingModule { }
|
97
angular/src/app/book-issue/book-issue.component.html
Normal file
97
angular/src/app/book-issue/book-issue.component.html
Normal file
@ -0,0 +1,97 @@
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-md-6">
|
||||
<h5 class="card-title">
|
||||
{{ 'Book-Issue' | abpLocalization }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="text-end col col-md-6">
|
||||
|
||||
<!-- Add the "new book" button here -->
|
||||
<div class="text-lg-end pt-2">
|
||||
<button id="create" class="btn btn-primary" type="button" (click)="createBookIssue()">
|
||||
<i class="fa fa-plus me-1"></i>
|
||||
<span>{{ "New Book Issue" | abpLocalization }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ngx-datatable [rows]="bookIssueList.items" [count]="bookIssueList.totalCount" [list]="list" default>
|
||||
|
||||
<ngx-datatable-column
|
||||
[name]="'::Actions' | abpLocalization"
|
||||
[maxWidth]="150"
|
||||
[sortable]="false"
|
||||
>
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
<div ngbDropdown container="body" class="d-inline-block">
|
||||
<button
|
||||
class="btn btn-primary btn-sm dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
ngbDropdownToggle
|
||||
>
|
||||
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
|
||||
</button>
|
||||
<div ngbDropdownMenu>
|
||||
<button ngbDropdownItem (click)="delete(row.bookIssueId)">
|
||||
{{ 'un Issue' | abpLocalization }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
|
||||
<ngx-datatable-column [name]="'Book Name' | abpLocalization" prop="bookName"></ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'Customer Name' | abpLocalization" prop="customerName">
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'Issue Date' | abpLocalization" prop="issueDate">
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
{{ row.issueDate | date }}
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add the modal here -->
|
||||
<abp-modal [(visible)]="isModalOpen">
|
||||
<ng-template #abpHeader>
|
||||
<h3> Book Issued </h3>
|
||||
</ng-template>
|
||||
<ng-template #abpBody>
|
||||
<form [formGroup]="form" (ngSubmit)="save()">
|
||||
<div class="mt-2">
|
||||
<label for="book-type">Book Name</label><span> * </span>
|
||||
<select class="form-control" id="book-type" formControlName="bookId">
|
||||
<option [ngValue]="null">Select a book name</option>
|
||||
<option [ngValue]="book.id" *ngFor="let book of dropDownbook"> {{ book.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="customer-name">Customer Name</label><span> * </span>
|
||||
<select class="form-control" id="customer-name" formControlName="customerId">
|
||||
<option [ngValue]="null">Select a customer name</option>
|
||||
<option [ngValue]="customer.id" *ngFor="let customer of dropDownCustomer"> {{ customer.firstName }} {{ customer.lastName}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
||||
|
||||
<ng-template #abpFooter>
|
||||
<button type="button" class="btn btn-secondary" abpClose>
|
||||
{{ '::Close' | abpLocalization }}
|
||||
</button>
|
||||
|
||||
<!--added save button-->
|
||||
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
|
||||
<i class="fa fa-check mr-1"></i>
|
||||
{{ '::Save' | abpLocalization }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</abp-modal>
|
23
angular/src/app/book-issue/book-issue.component.spec.ts
Normal file
23
angular/src/app/book-issue/book-issue.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BookIssueComponent } from './book-issue.component';
|
||||
|
||||
describe('BookIssueComponent', () => {
|
||||
let component: BookIssueComponent;
|
||||
let fixture: ComponentFixture<BookIssueComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [BookIssueComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(BookIssueComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
83
angular/src/app/book-issue/book-issue.component.ts
Normal file
83
angular/src/app/book-issue/book-issue.component.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ListService, PagedResultDto } from '@abp/ng.core';
|
||||
import { BookIssueDto, BookIssueListDto, BookIssueService } from '@proxy/book-issued';
|
||||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { BookDto, BookService } from '@proxy/books';
|
||||
import { CustomerDto, CustomerService } from '@proxy/customers';
|
||||
import { ConfirmationService,Confirmation } from '@abp/ng.theme.shared';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-issue',
|
||||
templateUrl: './book-issue.component.html',
|
||||
styleUrl: './book-issue.component.scss',
|
||||
providers: [ListService]
|
||||
})
|
||||
export class BookIssueComponent implements OnInit {
|
||||
isModalOpen = false;
|
||||
|
||||
form:FormGroup;
|
||||
dropDownbook= {} as Array<BookDto>;
|
||||
dropDownCustomer= {} as Array<CustomerDto>;
|
||||
bookIssueList = { items: [], totalCount: 0 } as PagedResultDto<BookIssueListDto>;
|
||||
|
||||
constructor(public readonly list: ListService,
|
||||
private bookIssuedService: BookIssueService,
|
||||
private bookService: BookService,
|
||||
private customerService: CustomerService,
|
||||
private fb: FormBuilder,
|
||||
private confirmation: ConfirmationService ) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dropdowninitiale();
|
||||
|
||||
const bookStreamCreator = (query) => this.bookIssuedService.getList(query);
|
||||
|
||||
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
|
||||
this.bookIssueList = response;
|
||||
});
|
||||
}
|
||||
|
||||
createBookIssue() {
|
||||
this.buildForm();
|
||||
this.isModalOpen = true;
|
||||
}
|
||||
|
||||
buildForm() {
|
||||
|
||||
this.form = this.fb.group({
|
||||
bookId: ['', Validators.required],
|
||||
customerId: ['', Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.form.invalid) {
|
||||
return;
|
||||
}
|
||||
this.bookIssuedService.create(this.form.value).subscribe(() => {
|
||||
this.isModalOpen = false;
|
||||
this.form.reset();
|
||||
this.list.get();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
dropdowninitiale(){
|
||||
this.bookService.getBookDropDown().subscribe((response)=>{
|
||||
this.dropDownbook = response;
|
||||
|
||||
});
|
||||
this.customerService.getcustomerDropDown().subscribe((response)=>{
|
||||
this.dropDownCustomer = response;
|
||||
|
||||
});
|
||||
}
|
||||
delete(bookIssueId: number) {
|
||||
this.confirmation.warn('::AreYouSureToUnIssue', '::AreYouSure').subscribe((status) => {
|
||||
if (status === Confirmation.Status.confirm) {
|
||||
this.bookIssuedService.delete(bookIssueId).subscribe(() => this.list.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
19
angular/src/app/book-issue/book-issue.module.ts
Normal file
19
angular/src/app/book-issue/book-issue.module.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { BookIssueRoutingModule } from './book-issue-routing.module';
|
||||
import { BookIssueComponent } from './book-issue.component';
|
||||
|
||||
import{SharedModule} from '../shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
BookIssueComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BookIssueRoutingModule,
|
||||
SharedModule
|
||||
]
|
||||
})
|
||||
export class BookIssueModule { }
|
12
angular/src/app/book/book-routing.module.ts
Normal file
12
angular/src/app/book/book-routing.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { BookComponent } from './book.component';
|
||||
import { authGuard, permissionGuard } from '@abp/ng.core';
|
||||
|
||||
const routes: Routes = [{ path: '', component: BookComponent, canActivate: [authGuard, permissionGuard] }];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class BookRoutingModule { }
|
122
angular/src/app/book/book.component.html
Normal file
122
angular/src/app/book/book.component.html
Normal file
@ -0,0 +1,122 @@
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-md-6">
|
||||
<h5 class="card-title">
|
||||
{{ '::Menu:Books' | abpLocalization }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="text-end col col-md-6">
|
||||
|
||||
<!-- Add the "new book" button here -->
|
||||
<div class="text-lg-end pt-2">
|
||||
<button id="create" class="btn btn-primary" type="button" (click)="createBook()">
|
||||
<i class="fa fa-plus me-1"></i>
|
||||
<span>{{ "::NewBook" | abpLocalization }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ngx-datatable [rows]="book.items" [count]="book.totalCount" [list]="list" default>
|
||||
<ngx-datatable-column
|
||||
[name]="'::Actions' | abpLocalization"
|
||||
[maxWidth]="150"
|
||||
[sortable]="false"
|
||||
>
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
<div ngbDropdown container="body" class="d-inline-block">
|
||||
<button
|
||||
class="btn btn-primary btn-sm dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
ngbDropdownToggle
|
||||
>
|
||||
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
|
||||
</button>
|
||||
<div ngbDropdownMenu>
|
||||
<button ngbDropdownItem (click)="editBook(row.id)">
|
||||
{{ '::Edit' | abpLocalization }}
|
||||
</button>
|
||||
<button ngbDropdownItem (click)="delete(row.id)">
|
||||
{{ '::Delete' | abpLocalization }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'::Name' | abpLocalization" prop="name"></ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'::Type' | abpLocalization" prop="type">
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
{{ '::Enum:BookType.' + row.type | abpLocalization }}
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'::PublishDate' | abpLocalization" prop="publishDate">
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
{{ row.publishDate | date }}
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'::Price' | abpLocalization" prop="price">
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
{{ row.price | currency }}
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add the modal here -->
|
||||
<abp-modal [(visible)]="isModalOpen">
|
||||
<ng-template #abpHeader>
|
||||
<h3>{{ '::NewBook' | abpLocalization }}</h3>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #abpBody>
|
||||
<form [formGroup]="form" (ngSubmit)="save()">
|
||||
<div class="mt-2">
|
||||
<label for="book-name">Name</label><span> * </span>
|
||||
<input type="text" id="book-name" class="form-control" formControlName="name" autofocus />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-price">Price</label><span> * </span>
|
||||
<input type="number" id="book-price" class="form-control" formControlName="price" />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="book-type">Type</label><span> * </span>
|
||||
<select class="form-control" id="book-type" formControlName="type">
|
||||
<option [ngValue]="null">Select a book type</option>
|
||||
<option [ngValue]="type.value" *ngFor="let type of bookTypes"> {{ '::Enum:BookType.' + type.value | abpLocalization }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label>Publish date</label><span> * </span>
|
||||
<input
|
||||
#datepicker="ngbDatepicker"
|
||||
class="form-control"
|
||||
name="datepicker"
|
||||
formControlName="publishDate"
|
||||
ngbDatepicker
|
||||
(click)="datepicker.toggle()"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
||||
|
||||
<ng-template #abpFooter>
|
||||
<button type="button" class="btn btn-secondary" abpClose>
|
||||
{{ '::Close' | abpLocalization }}
|
||||
</button>
|
||||
|
||||
<!--added save button-->
|
||||
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
|
||||
<i class="fa fa-check mr-1"></i>
|
||||
{{ '::Save' | abpLocalization }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</abp-modal>
|
0
angular/src/app/book/book.component.scss
Normal file
0
angular/src/app/book/book.component.scss
Normal file
23
angular/src/app/book/book.component.spec.ts
Normal file
23
angular/src/app/book/book.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BookComponent } from './book.component';
|
||||
|
||||
describe('BookComponent', () => {
|
||||
let component: BookComponent;
|
||||
let fixture: ComponentFixture<BookComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [BookComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(BookComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
88
angular/src/app/book/book.component.ts
Normal file
88
angular/src/app/book/book.component.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { ListService, PagedResultDto } from '@abp/ng.core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { BookService, BookDto, bookTypeOptions } from '@proxy/books';
|
||||
import { NgbDateNativeAdapter, NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book',
|
||||
templateUrl: './book.component.html',
|
||||
styleUrls: ['./book.component.scss'],
|
||||
providers: [ListService,
|
||||
{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter } // add this line
|
||||
],
|
||||
})
|
||||
export class BookComponent implements OnInit {
|
||||
book = { items: [], totalCount: 0 } as PagedResultDto<BookDto>;
|
||||
selectedBook = {} as BookDto; // declare selectedBook
|
||||
isModalOpen = false; // add this line
|
||||
form: FormGroup; // add this line
|
||||
bookTypes = bookTypeOptions;
|
||||
|
||||
constructor(public readonly list: ListService, private bookService: BookService, private fb: FormBuilder,
|
||||
private confirmation: ConfirmationService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
debugger;
|
||||
|
||||
const bookStreamCreator = (query) => this.bookService.getList(query);
|
||||
|
||||
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
|
||||
this.book = response;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// add new method
|
||||
createBook() {
|
||||
this.buildForm(); // add this line
|
||||
this.selectedBook = {} as BookDto; // reset the selected book
|
||||
|
||||
this.isModalOpen = true;
|
||||
}
|
||||
buildForm() {
|
||||
this.form = this.fb.group({
|
||||
name: ['', Validators.required],
|
||||
type: [null, Validators.required],
|
||||
publishDate: [null, Validators.required],
|
||||
price: [null, Validators.required],
|
||||
});
|
||||
}
|
||||
save() {
|
||||
if (this.form.invalid) {
|
||||
return;
|
||||
}
|
||||
const request = this.selectedBook.id
|
||||
? this.bookService.update(this.selectedBook.id, this.form.value)
|
||||
: this.bookService.create(this.form.value);
|
||||
|
||||
request.subscribe(() => {
|
||||
this.isModalOpen = false;
|
||||
this.form.reset();
|
||||
this.list.get();
|
||||
});
|
||||
}
|
||||
|
||||
// Add editBook method
|
||||
editBook(id: string) {
|
||||
this.bookService.get(id).subscribe((book) => {
|
||||
this.selectedBook = book;
|
||||
this.buildForm();
|
||||
this.form.controls["name"].setValue(this.selectedBook.name);
|
||||
this.form.controls["type"].setValue(this.selectedBook.type);
|
||||
this.form.controls["publishDate"].setValue(this.selectedBook.publishDate);
|
||||
this.form.controls["price"].setValue(this.selectedBook.price);
|
||||
this.isModalOpen = true;
|
||||
});
|
||||
}
|
||||
|
||||
delete(id: string) {
|
||||
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
|
||||
if (status === Confirmation.Status.confirm) {
|
||||
this.bookService.delete(id).subscribe(() => this.list.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
21
angular/src/app/book/book.module.ts
Normal file
21
angular/src/app/book/book.module.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { BookRoutingModule } from './book-routing.module';
|
||||
import { BookComponent } from './book.component';
|
||||
import{SharedModule} from '../shared/shared.module';
|
||||
import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; // add this line
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
BookComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BookRoutingModule,
|
||||
SharedModule,
|
||||
NgbDatepickerModule
|
||||
]
|
||||
})
|
||||
export class BookModule { }
|
13
angular/src/app/customer/customer-routing.module.ts
Normal file
13
angular/src/app/customer/customer-routing.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { CustomerComponent } from './customer.component';
|
||||
import { authGuard, permissionGuard } from '@abp/ng.core';
|
||||
|
||||
|
||||
const routes: Routes = [{ path: '', component: CustomerComponent,canActivate: [authGuard, permissionGuard] }];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class CustomerRoutingModule { }
|
101
angular/src/app/customer/customer.component.html
Normal file
101
angular/src/app/customer/customer.component.html
Normal file
@ -0,0 +1,101 @@
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-md-6">
|
||||
<h5 class="card-title">
|
||||
{{ 'customer' | abpLocalization }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="text-end col col-md-6">
|
||||
|
||||
<!-- Add the "new book" button here -->
|
||||
<div class="text-lg-end pt-2">
|
||||
<button id="create" class="btn btn-primary" type="button" (click)="createCustomer()">
|
||||
<i class="fa fa-plus me-1"></i>
|
||||
<span>{{ "New Customer" | abpLocalization }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ngx-datatable [rows]="customer.items" [count]="customer.totalCount" [list]="list" default>
|
||||
<ngx-datatable-column
|
||||
[name]="'::Actions' | abpLocalization"
|
||||
[maxWidth]="150"
|
||||
[sortable]="false"
|
||||
>
|
||||
<ng-template let-row="row" ngx-datatable-cell-template>
|
||||
<div ngbDropdown container="body" class="d-inline-block">
|
||||
<button
|
||||
class="btn btn-primary btn-sm dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
ngbDropdownToggle
|
||||
>
|
||||
<i class="fa fa-cog me-1"></i>{{ '::Actions' | abpLocalization }}
|
||||
</button>
|
||||
<div ngbDropdownMenu>
|
||||
<button ngbDropdownItem (click)="editCustomer(row.id)">
|
||||
{{ '::Edit' | abpLocalization }}
|
||||
</button>
|
||||
<button ngbDropdownItem (click)="delete(row.id)">
|
||||
{{ '::Delete' | abpLocalization }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'first Name' | abpLocalization" prop="firstName"></ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'Last Name' | abpLocalization" prop="lastName">
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'::Address' | abpLocalization" prop="address">
|
||||
</ngx-datatable-column>
|
||||
<ngx-datatable-column [name]="'::Phone' | abpLocalization" prop="phone">
|
||||
</ngx-datatable-column>
|
||||
</ngx-datatable>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add the modal here -->
|
||||
<abp-modal [(visible)]="isModalOpen">
|
||||
<ng-template #abpHeader>
|
||||
<h3>{{ (selectedcustomer.id ? '::Edit' : '::New Customer' ) | abpLocalization }}</h3>
|
||||
</ng-template>
|
||||
<ng-template #abpBody>
|
||||
<form [formGroup]="form" (ngSubmit)="save()">
|
||||
<div class="mt-2">
|
||||
<label for="customer-first-name">First Name</label><span> * </span>
|
||||
<input type="text" id="customer-first-name" class="form-control" formControlName="firstName" autofocus />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="customer-last-name">Last Name</label><span> * </span>
|
||||
<input type="text" id="customer-last-name" class="form-control" formControlName="lastName" />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="customer-phone-name">Phone</label><span> * </span>
|
||||
<input type="text" id="customer-phone-name" class="form-control" formControlName="phone" />
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<label for="customer-address-name">Address</label><span> * </span>
|
||||
<input type="text" id="customer-address-name" class="form-control" formControlName="address" />
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
||||
|
||||
<ng-template #abpFooter>
|
||||
<button type="button" class="btn btn-secondary" abpClose>
|
||||
{{ '::Close' | abpLocalization }}
|
||||
</button>
|
||||
|
||||
<!--added save button-->
|
||||
<button class="btn btn-primary" (click)="save()" [disabled]="form.invalid">
|
||||
<i class="fa fa-check mr-1"></i>
|
||||
{{ '::Save' | abpLocalization }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</abp-modal>
|
0
angular/src/app/customer/customer.component.scss
Normal file
0
angular/src/app/customer/customer.component.scss
Normal file
23
angular/src/app/customer/customer.component.spec.ts
Normal file
23
angular/src/app/customer/customer.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CustomerComponent } from './customer.component';
|
||||
|
||||
describe('CustomerComponent', () => {
|
||||
let component: CustomerComponent;
|
||||
let fixture: ComponentFixture<CustomerComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CustomerComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CustomerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
92
angular/src/app/customer/customer.component.ts
Normal file
92
angular/src/app/customer/customer.component.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ListService, PagedResultDto } from '@abp/ng.core';
|
||||
import { CustomerDto, CustomerService } from '@proxy/customers';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { ConfirmationService, Confirmation } from '@abp/ng.theme.shared';
|
||||
|
||||
@Component({
|
||||
selector: 'app-customer',
|
||||
templateUrl: './customer.component.html',
|
||||
styleUrl: './customer.component.scss',
|
||||
providers: [ListService]
|
||||
})
|
||||
export class CustomerComponent implements OnInit {
|
||||
customer = { items: [], totalCount: 0 } as PagedResultDto<CustomerDto>;
|
||||
isModalOpen = false;
|
||||
form: FormGroup;
|
||||
selectedcustomer = {} as CustomerDto;
|
||||
constructor(public readonly list: ListService,
|
||||
private customerService: CustomerService,
|
||||
private fb: FormBuilder,
|
||||
private confirmation: ConfirmationService ) {}
|
||||
|
||||
ngOnInit() {
|
||||
debugger;
|
||||
|
||||
const bookStreamCreator = (query) => this.customerService.getList(query);
|
||||
|
||||
this.list.hookToQuery(bookStreamCreator).subscribe((response) => {
|
||||
this.customer = response;
|
||||
});
|
||||
}
|
||||
// add new method
|
||||
createCustomer() {
|
||||
this.selectedcustomer = {} as CustomerDto;
|
||||
this.buildForm();
|
||||
this.isModalOpen = true;
|
||||
}
|
||||
editCustomer(id: number) {
|
||||
this.customerService.get(id).subscribe((customer) => {
|
||||
debugger;
|
||||
this.selectedcustomer = customer;
|
||||
this.buildForm();
|
||||
this.isModalOpen = true;
|
||||
});
|
||||
}
|
||||
|
||||
buildForm() {
|
||||
|
||||
this.form = this.fb.group({
|
||||
firstName: [this.selectedcustomer.firstName || '', Validators.required],
|
||||
lastName: [this.selectedcustomer.lastName, Validators.required],
|
||||
phone: [this.selectedcustomer.phone, Validators.required],
|
||||
address: [this.selectedcustomer.address, Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
// add save method
|
||||
save() {
|
||||
if (this.form.invalid) {
|
||||
return;
|
||||
}
|
||||
debugger;
|
||||
const request = this.selectedcustomer.id
|
||||
? this.customerService.update(this.selectedcustomer.id, this.form.value)
|
||||
: this.customerService.create(this.form.value);
|
||||
if(this.selectedcustomer.id){
|
||||
|
||||
this.customerService.update(this.selectedcustomer.id,this.form.value).subscribe(() => {
|
||||
this.isModalOpen = false;
|
||||
this.form.reset();
|
||||
this.list.get();
|
||||
});
|
||||
}
|
||||
else{
|
||||
this.customerService.create(this.form.value).subscribe(() => {
|
||||
this.isModalOpen = false;
|
||||
this.form.reset();
|
||||
this.list.get();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete(id: number) {
|
||||
this.confirmation.warn('::AreYouSureToDelete', '::AreYouSure').subscribe((status) => {
|
||||
if (status === Confirmation.Status.confirm) {
|
||||
this.customerService.delete(id).subscribe(() => this.list.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
20
angular/src/app/customer/customer.module.ts
Normal file
20
angular/src/app/customer/customer.module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { CustomerRoutingModule } from './customer-routing.module';
|
||||
import { CustomerComponent } from './customer.component';
|
||||
|
||||
import{SharedModule} from '../shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CustomerComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CustomerRoutingModule,
|
||||
SharedModule
|
||||
|
||||
]
|
||||
})
|
||||
export class CustomerModule { }
|
11
angular/src/app/home/home-routing.module.ts
Normal file
11
angular/src/app/home/home-routing.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { HomeComponent } from './home.component';
|
||||
|
||||
const routes: Routes = [{ path: '', component: HomeComponent }];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class HomeRoutingModule {}
|
362
angular/src/app/home/home.component.html
Normal file
362
angular/src/app/home/home.component.html
Normal file
@ -0,0 +1,362 @@
|
||||
<div class="container">
|
||||
<div class="p-5 text-center">
|
||||
<div class="d-inline-block bg-success text-white p-1 h5 rounded mb-4" role="alert">
|
||||
<h5 class="m-1">
|
||||
<i class="fas fa-rocket" aria-hidden="true"></i> Congratulations, <strong>BookStore</strong> is
|
||||
successfully running!
|
||||
</h5>
|
||||
</div>
|
||||
<h1>{{ '::Welcome' | abpLocalization }}</h1>
|
||||
|
||||
<p class="lead px-lg-5 mx-lg-5">{{ '::LongWelcomeMessage' | abpLocalization }}</p>
|
||||
|
||||
<a *ngIf="!hasLoggedIn" (click)="login()" class="px-4 btn btn-primary ms-1" role="button"
|
||||
><i class="fa fa-sign-in" aria-hidden="true"></i> {{ 'AbpAccount::Login' | abpLocalization }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-auto text-center">
|
||||
<img src="https://abp.io/assets/png/mastering-abp-framework.webp" style="max-width: 400px;"
|
||||
class="w-100 mb-5 my-md-3">
|
||||
</div>
|
||||
<div class="col-md d-flex align-items-center">
|
||||
<div class="pe-0 pe-md-4">
|
||||
<small class="text-uppercase text-muted">THE OFFICIAL GUIDE</small>
|
||||
<h2 class="mb-4">Mastering ABP Framework</h2>
|
||||
<p class="mb-4">Written by the creator of the ABP Framework, this book will help you gain a complete
|
||||
understanding of the framework and modern web application development techniques.</p>
|
||||
<div class="mb-4">
|
||||
<a href="https://www.amazon.com/gp/product/B097Z2DM8Q/ref=dbs_a_def_rwt_hsch_vapi_tkin_p1_i0"
|
||||
class="btn btn-success mb-1">
|
||||
Buy on Amazon US
|
||||
</a>
|
||||
|
||||
<a href="https://www.packtpub.com/product/mastering-abp-framework/9781801079242"
|
||||
class="btn btn-primary mb-1">
|
||||
Buy on PACKT
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3 text-center">
|
||||
<h3>Let's improve your application!</h3>
|
||||
<p>Here are some links to help you get started:</p>
|
||||
</div>
|
||||
<div class="card mt-4 mb-5">
|
||||
<div class="card-body">
|
||||
<div class="row text-center justify-content-md-center">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
starterLinkTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Learn the ABP Framework',
|
||||
description:
|
||||
'Explore the compherensive documentation to learn how to build a modern web application.',
|
||||
links: [
|
||||
{
|
||||
href: 'https://docs.abp.io/en/abp/latest?ref=tmpl',
|
||||
label: 'See Documents'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
starterLinkTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Samples',
|
||||
description: 'See the example projects built with the ABP Framework.',
|
||||
links: [
|
||||
{
|
||||
href: 'https://docs.abp.io/en/abp/latest/Samples/Index?ref=tmpl',
|
||||
label: 'All samples'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
starterLinkTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'ABP Community',
|
||||
description: 'Get involved with a vibrant community and become a contributor.',
|
||||
links: [
|
||||
{
|
||||
href: 'https://community.abp.io/',
|
||||
label: 'Community'
|
||||
},
|
||||
{
|
||||
href: 'https://docs.abp.io/en/abp/latest/Contribution/Index?ref=tmpl',
|
||||
label: 'Contribute'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
</div>
|
||||
<div class="row text-center mt-lg-3 justify-content-md-center">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
starterLinkTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'ABP Blog',
|
||||
description: 'Take a look at our recently published articles.',
|
||||
links: [
|
||||
{
|
||||
href: 'https://blog.abp.io/abp?ref=tmpl',
|
||||
label: 'See Blog'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-template #githubButtonsTemplate>
|
||||
<p class="mb-1">
|
||||
<iframe
|
||||
scrolling="no"
|
||||
src="https://buttons.github.io/buttons.html#href=https%3A%2F%2Fgithub.com%2Fabpframework%2Fabp&title=&aria-label=Star%20tabalinas%2Fjsgrid%20on%20GitHub&data-icon=octicon-star&data-text=Star&data-size=large&data-show-count=true"
|
||||
style="
|
||||
width: 122px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
"
|
||||
></iframe>
|
||||
<iframe
|
||||
scrolling="no"
|
||||
src="https://buttons.github.io/buttons.html#href=https%3A%2F%2Fgithub.com%2Fabpframework%2Fabp%2Fissues&title=&aria-label=Issue%20tabalinas%2Fjsgrid%20on%20GitHub&data-icon=octicon-issue-opened&data-text=Issue&data-size=large"
|
||||
style="
|
||||
width: 72px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
"
|
||||
></iframe>
|
||||
|
||||
<iframe
|
||||
scrolling="no"
|
||||
src="https://buttons.github.io/buttons.html#href=https%3A%2F%2Fgithub.com%2Fabpframework%2Fabp%2Ffork&title=&aria-label=Fork%20tabalinas%2Fjsgrid%20on%20GitHub&data-icon=octicon-repo-forked&data-text=Fork&data-size=large&"
|
||||
style="width: 72px; height: 28px; border: none; display: inline-block"
|
||||
></iframe>
|
||||
</p>
|
||||
</ng-template>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
starterLinkTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Github',
|
||||
description:
|
||||
'Do you love the ABP Framework? Please <strong>give a star</strong> to support it!',
|
||||
links: [
|
||||
{
|
||||
href: 'https://github.com/abpframework/abp/issues/new?template=feature.md',
|
||||
label: 'Request a feature'
|
||||
}
|
||||
],
|
||||
customTemplate: githubButtonsTemplate
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
starterLinkTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Stackoverflow',
|
||||
description: 'See answers to previously asked questions or ask a new one.',
|
||||
links: [
|
||||
{
|
||||
href: 'https://stackoverflow.com/questions/tagged/abp',
|
||||
label: 'Questions'
|
||||
},
|
||||
{
|
||||
href: 'https://stackoverflow.com/questions/ask',
|
||||
label: 'Ask a Question'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 my-3 text-center">
|
||||
<h3>Meet the ABP Commercial</h3>
|
||||
<p>A Complete Web Application Platform Built on the ABP Framework</p>
|
||||
</div>
|
||||
|
||||
<div class="card mt-4 mb-5">
|
||||
<div class="card-body">
|
||||
<p class="px-lg-5 mx-lg-5 py-3 text-center">
|
||||
<a href="https://commercial.abp.io/" target="_blank">ABP Commercial</a> is a platform based
|
||||
on the open source ABP framework. It provides pre-built application modules, rapid
|
||||
application development tooling, professional UI themes, premium support and more.
|
||||
</p>
|
||||
|
||||
<div class="row text-center justify-content-md-center">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
featuresTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Startup Templates',
|
||||
href: 'https://commercial.abp.io/startup-templates?ref=tmpl'
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
featuresTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Application Modules',
|
||||
href: 'https://commercial.abp.io/modules?ref=tmpl'
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
featuresTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Developer<br />Tools',
|
||||
href: 'https://commercial.abp.io/tools?ref=tmpl'
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
featuresTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'UI<br />Themes',
|
||||
href: 'https://commercial.abp.io/themes?ref=tmpl'
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
featuresTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Premium Support',
|
||||
href: 'https://support.abp.io/QA/Questions?ref=tmpl'
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
featuresTemplate;
|
||||
context: {
|
||||
$implicit: {
|
||||
title: 'Additional Services',
|
||||
href: 'https://commercial.abp.io/additional-services?ref=tmpl'
|
||||
}
|
||||
}
|
||||
"
|
||||
></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-5 text-center">
|
||||
<p class="align-middle">
|
||||
<a href="https://twitter.com/abpframework" target="_blank" class="mx-2"
|
||||
><i class="fa fa-twitter" aria-hidden="true"></i><span class="text-secondary"> Abp Framework</span></a
|
||||
>
|
||||
<a href="https://twitter.com/abpcommercial" target="_blank" class="mx-2"
|
||||
><i class="fa fa-twitter" aria-hidden="true"></i><span class="text-secondary"> Abp Commercial</span></a
|
||||
>
|
||||
<a href="https://github.com/abpframework/abp" target="_blank" class="mx-2"
|
||||
><i class="fa fa-github" aria-hidden="true"></i><span class="text-secondary"> abpframework</span></a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #starterLinkTemplate let-context>
|
||||
<div class="col-lg-4 border-start">
|
||||
<div class="p-4">
|
||||
<h5 class="mb-3">
|
||||
<i class="fas fa-cubes text-secondary d-block my-3 fa-2x" aria-hidden="true"></i> {{ context.title }}
|
||||
</h5>
|
||||
<p [innerHTML]="context.description"></p>
|
||||
<ng-container
|
||||
*ngIf="context.customTemplate"
|
||||
[ngTemplateOutlet]="context.customTemplate"
|
||||
></ng-container>
|
||||
<a
|
||||
*ngFor="let link of context.links"
|
||||
[href]="link.href"
|
||||
target="_blank"
|
||||
class="btn btn-link px-1"
|
||||
>{{ link.label }} <i class="fas fa-chevron-right" aria-hidden="true"></i
|
||||
></a>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #featuresTemplate let-context>
|
||||
<div class="col-lg-2 border-start">
|
||||
<div class="p-3">
|
||||
<h6>
|
||||
<i class="fas fa-plus d-block mb-3 fa- 2x text-secondary" aria-hidden="true"></i>
|
||||
<span [innerHTML]="context.title"></span>
|
||||
<a [href]="context.href" target="_blank" class="d-block mt-2 btn btn-sm btn-link"
|
||||
>Details <i class="fas fa-chevron-right" aria-hidden="true"></i
|
||||
></a>
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<style scoped>
|
||||
.col-lg-2.border-start:nth-of-type(6n + 1) {
|
||||
border-left: 0 !important;
|
||||
}
|
||||
|
||||
.col-lg-4.border-start:nth-of-type(3n + 1) {
|
||||
border-left: 0 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.border-start {
|
||||
border-left: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
1
angular/src/app/home/home.component.scss
Normal file
1
angular/src/app/home/home.component.scss
Normal file
@ -0,0 +1 @@
|
||||
/* Styles for the home component */
|
99
angular/src/app/home/home.component.spec.ts
Normal file
99
angular/src/app/home/home.component.spec.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { CoreTestingModule } from "@abp/ng.core/testing";
|
||||
import { ThemeSharedTestingModule } from "@abp/ng.theme.shared/testing";
|
||||
import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
|
||||
import { NgxValidateCoreModule } from "@ngx-validate/core";
|
||||
import { HomeComponent } from "./home.component";
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { AuthService } from '@abp/ng.core';
|
||||
|
||||
|
||||
|
||||
describe("HomeComponent", () => {
|
||||
let fixture: ComponentFixture<HomeComponent>;
|
||||
const mockOAuthService = jasmine.createSpyObj('OAuthService', ['hasValidAccessToken'])
|
||||
const mockAuthService = jasmine.createSpyObj('AuthService', ['navigateToLogin'])
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [HomeComponent],
|
||||
imports: [
|
||||
CoreTestingModule.withConfig(),
|
||||
ThemeSharedTestingModule.withConfig(),
|
||||
NgxValidateCoreModule,
|
||||
],
|
||||
providers: [
|
||||
/* mock providers here */
|
||||
{
|
||||
provide: OAuthService,
|
||||
useValue: mockOAuthService
|
||||
},
|
||||
{
|
||||
provide: AuthService,
|
||||
useValue: mockAuthService
|
||||
}
|
||||
],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it("should be initiated", () => {
|
||||
expect(fixture.componentInstance).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe('when login state is true', () => {
|
||||
beforeAll(() => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(true)
|
||||
});
|
||||
|
||||
it("hasLoggedIn should be true", () => {
|
||||
|
||||
expect(fixture.componentInstance.hasLoggedIn).toBeTrue();
|
||||
expect(mockOAuthService.hasValidAccessToken).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("button should not be exists", () => {
|
||||
const element = fixture.nativeElement
|
||||
const button = element.querySelector('[role="button"]')
|
||||
expect(button).toBeNull()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when login state is false', () => {
|
||||
beforeAll(() => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(false)
|
||||
});
|
||||
|
||||
it("hasLoggedIn should be false", () => {
|
||||
|
||||
expect(fixture.componentInstance.hasLoggedIn).toBeFalse();
|
||||
expect(mockOAuthService.hasValidAccessToken).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("button should be exists", () => {
|
||||
const element = fixture.nativeElement
|
||||
const button = element.querySelector('[role="button"]')
|
||||
expect(button).toBeDefined()
|
||||
})
|
||||
describe('when button clicked', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const element = fixture.nativeElement
|
||||
const button = element.querySelector('[role="button"]')
|
||||
button.click()
|
||||
});
|
||||
|
||||
it("navigateToLogin have been called", () => {
|
||||
expect(mockAuthService.navigateToLogin).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
});
|
19
angular/src/app/home/home.component.ts
Normal file
19
angular/src/app/home/home.component.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { AuthService } from '@abp/ng.core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss'],
|
||||
})
|
||||
export class HomeComponent {
|
||||
get hasLoggedIn(): boolean {
|
||||
return this.authService.isAuthenticated;
|
||||
}
|
||||
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
login() {
|
||||
this.authService.navigateToLogin();
|
||||
}
|
||||
}
|
10
angular/src/app/home/home.module.ts
Normal file
10
angular/src/app/home/home.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { HomeRoutingModule } from './home-routing.module';
|
||||
import { HomeComponent } from './home.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [HomeComponent],
|
||||
imports: [SharedModule, HomeRoutingModule],
|
||||
})
|
||||
export class HomeModule {}
|
17
angular/src/app/proxy/README.md
Normal file
17
angular/src/app/proxy/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Proxy Generation Output
|
||||
|
||||
This directory includes the output of the latest proxy generation.
|
||||
The files and folders in it will be overwritten when proxy generation is run again.
|
||||
Therefore, please do not place your own content in this folder.
|
||||
|
||||
In addition, `generate-proxy.json` works like a lock file.
|
||||
It includes information used by the proxy generator, so please do not delete or modify it.
|
||||
|
||||
Finally, the name of the files and folders should not be changed for two reasons:
|
||||
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content.
|
||||
- ABP Suite generates files which include imports from this folder.
|
||||
|
||||
> **Important Notice:** If you are building a module and are planning to publish to npm,
|
||||
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case,
|
||||
> please make sure you export files directly and not from barrel exports. In other words,
|
||||
> do not include index.ts exports in your public-api.ts exports.
|
56
angular/src/app/proxy/authors/author.service.ts
Normal file
56
angular/src/app/proxy/authors/author.service.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import type { AuthorDto, CreateAuthorDto, GetAuthorListDto, UpdateAuthorDto } from './models';
|
||||
import { RestService, Rest } from '@abp/ng.core';
|
||||
import type { PagedResultDto } from '@abp/ng.core';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthorService {
|
||||
apiName = 'Default';
|
||||
|
||||
|
||||
create = (input: CreateAuthorDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, AuthorDto>({
|
||||
method: 'POST',
|
||||
url: '/api/app/author',
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
delete = (id: string, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'DELETE',
|
||||
url: `/api/app/author/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
get = (id: string, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, AuthorDto>({
|
||||
method: 'GET',
|
||||
url: `/api/app/author/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
getList = (input: GetAuthorListDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, PagedResultDto<AuthorDto>>({
|
||||
method: 'GET',
|
||||
url: '/api/app/author',
|
||||
params: { filter: input.filter, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
update = (id: string, input: UpdateAuthorDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'PUT',
|
||||
url: `/api/app/author/${id}`,
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
constructor(private restService: RestService) {}
|
||||
}
|
2
angular/src/app/proxy/authors/index.ts
Normal file
2
angular/src/app/proxy/authors/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './author.service';
|
||||
export * from './models';
|
23
angular/src/app/proxy/authors/models.ts
Normal file
23
angular/src/app/proxy/authors/models.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { EntityDto, PagedAndSortedResultRequestDto } from '@abp/ng.core';
|
||||
|
||||
export interface AuthorDto extends EntityDto<string> {
|
||||
name?: string;
|
||||
birthDate?: string;
|
||||
shortBio?: string;
|
||||
}
|
||||
|
||||
export interface CreateAuthorDto {
|
||||
name: string;
|
||||
birthDate: string;
|
||||
shortBio?: string;
|
||||
}
|
||||
|
||||
export interface GetAuthorListDto extends PagedAndSortedResultRequestDto {
|
||||
filter?: string;
|
||||
}
|
||||
|
||||
export interface UpdateAuthorDto {
|
||||
name: string;
|
||||
birthDate: string;
|
||||
shortBio?: string;
|
||||
}
|
55
angular/src/app/proxy/book-issued/book-issue.service.ts
Normal file
55
angular/src/app/proxy/book-issued/book-issue.service.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import type { BookIssueDto, BookIssueListDto } from './models';
|
||||
import { RestService, Rest } from '@abp/ng.core';
|
||||
import type { PagedResultDto } from '@abp/ng.core';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class BookIssueService {
|
||||
apiName = 'Default';
|
||||
|
||||
|
||||
create = (input: BookIssueDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, BookIssueDto>({
|
||||
method: 'POST',
|
||||
url: '/api/app/book-issue',
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
delete = (id: number, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'DELETE',
|
||||
url: `/api/app/book-issue/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
get = (id: number, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, BookIssueDto>({
|
||||
method: 'GET',
|
||||
url: `/api/app/book-issue/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
getList = (config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, PagedResultDto<BookIssueListDto>>({
|
||||
method: 'GET',
|
||||
url: '/api/app/book-issue',
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
update = (id: number, input: BookIssueDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'PUT',
|
||||
url: `/api/app/book-issue/${id}`,
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
constructor(private restService: RestService) {}
|
||||
}
|
2
angular/src/app/proxy/book-issued/index.ts
Normal file
2
angular/src/app/proxy/book-issued/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './book-issue.service';
|
||||
export * from './models';
|
13
angular/src/app/proxy/book-issued/models.ts
Normal file
13
angular/src/app/proxy/book-issued/models.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { EntityDto } from '@abp/ng.core';
|
||||
|
||||
export interface BookIssueDto extends EntityDto<number> {
|
||||
bookId?: string;
|
||||
customerId: number;
|
||||
}
|
||||
|
||||
export interface BookIssueListDto {
|
||||
bookIssueId: number;
|
||||
bookName?: string;
|
||||
customerName?: string;
|
||||
issueDate?: string;
|
||||
}
|
15
angular/src/app/proxy/books/book-type.enum.ts
Normal file
15
angular/src/app/proxy/books/book-type.enum.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { mapEnumToOptions } from '@abp/ng.core';
|
||||
|
||||
export enum BookType {
|
||||
Undefined = 0,
|
||||
Adventure = 1,
|
||||
Biography = 2,
|
||||
Dystopia = 3,
|
||||
Fantastic = 4,
|
||||
Horror = 5,
|
||||
Science = 6,
|
||||
ScienceFiction = 7,
|
||||
Poetry = 8,
|
||||
}
|
||||
|
||||
export const bookTypeOptions = mapEnumToOptions(BookType);
|
64
angular/src/app/proxy/books/book.service.ts
Normal file
64
angular/src/app/proxy/books/book.service.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import type { BookDto, CreateUpdateBookDto } from './models';
|
||||
import { RestService, Rest } from '@abp/ng.core';
|
||||
import type { PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class BookService {
|
||||
apiName = 'Default';
|
||||
|
||||
|
||||
create = (input: CreateUpdateBookDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, BookDto>({
|
||||
method: 'POST',
|
||||
url: '/api/app/book',
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
delete = (id: string, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'DELETE',
|
||||
url: `/api/app/book/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
get = (id: string, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, BookDto>({
|
||||
method: 'GET',
|
||||
url: `/api/app/book/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
getBookDropDown = (config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, BookDto[]>({
|
||||
method: 'GET',
|
||||
url: '/api/app/book/book-drop-down',
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
getList = (input: PagedAndSortedResultRequestDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, PagedResultDto<BookDto>>({
|
||||
method: 'GET',
|
||||
url: '/api/app/book',
|
||||
params: { sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
update = (id: string, input: CreateUpdateBookDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, BookDto>({
|
||||
method: 'PUT',
|
||||
url: `/api/app/book/${id}`,
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
constructor(private restService: RestService) {}
|
||||
}
|
3
angular/src/app/proxy/books/index.ts
Normal file
3
angular/src/app/proxy/books/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './book-type.enum';
|
||||
export * from './book.service';
|
||||
export * from './models';
|
16
angular/src/app/proxy/books/models.ts
Normal file
16
angular/src/app/proxy/books/models.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type { AuditedEntityDto } from '@abp/ng.core';
|
||||
import type { BookType } from './book-type.enum';
|
||||
|
||||
export interface BookDto extends AuditedEntityDto<string> {
|
||||
name?: string;
|
||||
type: BookType;
|
||||
publishDate?: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
export interface CreateUpdateBookDto {
|
||||
name: string;
|
||||
type: BookType;
|
||||
publishDate: string;
|
||||
price: number;
|
||||
}
|
63
angular/src/app/proxy/customers/customer.service.ts
Normal file
63
angular/src/app/proxy/customers/customer.service.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import type { CustomerDto } from './models';
|
||||
import { RestService, Rest } from '@abp/ng.core';
|
||||
import type { PagedResultDto } from '@abp/ng.core';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CustomerService {
|
||||
apiName = 'Default';
|
||||
|
||||
|
||||
create = (input: CustomerDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, CustomerDto>({
|
||||
method: 'POST',
|
||||
url: '/api/app/customer',
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
delete = (id: number, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'DELETE',
|
||||
url: `/api/app/customer/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
get = (id: number, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, CustomerDto>({
|
||||
method: 'GET',
|
||||
url: `/api/app/customer/${id}`,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
getList = (config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, PagedResultDto<CustomerDto>>({
|
||||
method: 'GET',
|
||||
url: '/api/app/customer',
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
getcustomerDropDown = (config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, CustomerDto[]>({
|
||||
method: 'GET',
|
||||
url: '/api/app/customer/customer-drop-down',
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
|
||||
update = (id: number, input: CustomerDto, config?: Partial<Rest.Config>) =>
|
||||
this.restService.request<any, void>({
|
||||
method: 'PUT',
|
||||
url: `/api/app/customer/${id}`,
|
||||
body: input,
|
||||
},
|
||||
{ apiName: this.apiName,...config });
|
||||
|
||||
constructor(private restService: RestService) {}
|
||||
}
|
2
angular/src/app/proxy/customers/index.ts
Normal file
2
angular/src/app/proxy/customers/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './customer.service';
|
||||
export * from './models';
|
8
angular/src/app/proxy/customers/models.ts
Normal file
8
angular/src/app/proxy/customers/models.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { EntityDto } from '@abp/ng.core';
|
||||
|
||||
export interface CustomerDto extends EntityDto<number> {
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
phone?: string;
|
||||
address?: string;
|
||||
}
|
10619
angular/src/app/proxy/generate-proxy.json
Normal file
10619
angular/src/app/proxy/generate-proxy.json
Normal file
File diff suppressed because it is too large
Load Diff
5
angular/src/app/proxy/index.ts
Normal file
5
angular/src/app/proxy/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import * as Authors from './authors';
|
||||
import * as BookIssued from './book-issued';
|
||||
import * as Books from './books';
|
||||
import * as Customers from './customers';
|
||||
export { Authors, BookIssued, Books, Customers };
|
53
angular/src/app/route.provider.ts
Normal file
53
angular/src/app/route.provider.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { RoutesService, eLayoutType } from '@abp/ng.core';
|
||||
import { APP_INITIALIZER } from '@angular/core';
|
||||
|
||||
export const APP_ROUTE_PROVIDER = [
|
||||
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
|
||||
];
|
||||
|
||||
function configureRoutes(routesService: RoutesService) {
|
||||
return () => {
|
||||
routesService.add([
|
||||
{
|
||||
path: '/',
|
||||
name: '::Menu:Home',
|
||||
iconClass: 'fas fa-home',
|
||||
order: 1,
|
||||
layout: eLayoutType.application,
|
||||
},
|
||||
{
|
||||
path: '/book-store',
|
||||
name: '::Menu:BookStore',
|
||||
iconClass: 'fas fa-book',
|
||||
order: 2,
|
||||
layout: eLayoutType.application,
|
||||
},
|
||||
{
|
||||
path: '/books',
|
||||
name: '::Menu:Books',
|
||||
parentName: '::Menu:BookStore',
|
||||
layout: eLayoutType.application,
|
||||
requiredPolicy: 'BookStore.Books',
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
path: '/customer',
|
||||
name: 'Customer',
|
||||
iconClass: 'fas fa-user',
|
||||
order: 2,
|
||||
layout: eLayoutType.application,
|
||||
requiredPolicy: 'BookStore.Customers',
|
||||
},
|
||||
{
|
||||
path: '/book-issue',
|
||||
name: 'book-issue',
|
||||
iconClass: 'fas fa-book',
|
||||
order: 2,
|
||||
layout: eLayoutType.application,
|
||||
requiredPolicy: 'BookStore.BookIssued',
|
||||
},
|
||||
]);
|
||||
};
|
||||
}
|
23
angular/src/app/shared/shared.module.ts
Normal file
23
angular/src/app/shared/shared.module.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { CoreModule } from '@abp/ng.core';
|
||||
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ThemeSharedModule } from '@abp/ng.theme.shared';
|
||||
import { NgxValidateCoreModule } from '@ngx-validate/core';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
CoreModule,
|
||||
ThemeSharedModule,
|
||||
NgbDropdownModule,
|
||||
NgxValidateCoreModule
|
||||
],
|
||||
exports: [
|
||||
CoreModule,
|
||||
ThemeSharedModule,
|
||||
NgbDropdownModule,
|
||||
NgxValidateCoreModule
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
export class SharedModule {}
|
0
angular/src/assets/.gitkeep
Normal file
0
angular/src/assets/.gitkeep
Normal file
BIN
angular/src/assets/images/logo/logo-light-thumbnail.png
Normal file
BIN
angular/src/assets/images/logo/logo-light-thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
angular/src/assets/images/logo/logo-light.png
Normal file
BIN
angular/src/assets/images/logo/logo-light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
26
angular/src/environments/environment.prod.ts
Normal file
26
angular/src/environments/environment.prod.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Environment } from '@abp/ng.core';
|
||||
|
||||
const baseUrl = 'http://localhost:4200';
|
||||
|
||||
export const environment = {
|
||||
production: true,
|
||||
application: {
|
||||
baseUrl,
|
||||
name: 'BookStore',
|
||||
logoUrl: '',
|
||||
},
|
||||
oAuthConfig: {
|
||||
issuer: 'https://localhost:44356/',
|
||||
redirectUri: baseUrl,
|
||||
clientId: 'BookStore_App',
|
||||
responseType: 'code',
|
||||
scope: 'offline_access BookStore',
|
||||
requireHttps: true
|
||||
},
|
||||
apis: {
|
||||
default: {
|
||||
url: 'https://localhost:44356',
|
||||
rootNamespace: 'Acme.BookStore',
|
||||
},
|
||||
},
|
||||
} as Environment;
|
26
angular/src/environments/environment.ts
Normal file
26
angular/src/environments/environment.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Environment } from '@abp/ng.core';
|
||||
|
||||
const baseUrl = 'http://localhost:4200';
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
application: {
|
||||
baseUrl,
|
||||
name: 'BookStore',
|
||||
logoUrl: '',
|
||||
},
|
||||
oAuthConfig: {
|
||||
issuer: 'https://localhost:44356/',
|
||||
redirectUri: baseUrl,
|
||||
clientId: 'BookStore_App',
|
||||
responseType: 'code',
|
||||
scope: 'offline_access BookStore',
|
||||
requireHttps: true,
|
||||
},
|
||||
apis: {
|
||||
default: {
|
||||
url: 'https://localhost:44356',
|
||||
rootNamespace: 'Acme.BookStore',
|
||||
},
|
||||
},
|
||||
} as Environment;
|
BIN
angular/src/favicon.ico
Normal file
BIN
angular/src/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
16
angular/src/index.html
Normal file
16
angular/src/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>BookStore</title>
|
||||
<base href="/" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<app-root>
|
||||
<div class="donut centered"></div>
|
||||
</app-root>
|
||||
</body>
|
||||
</html>
|
13
angular/src/main.ts
Normal file
13
angular/src/main.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
54
angular/src/polyfills.ts
Normal file
54
angular/src/polyfills.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js'; // Included with Angular CLI.
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
/******************************************************************
|
||||
* Load `$localize` - used if i18n tags appear in Angular templates.
|
||||
*/
|
||||
import '@angular/localize/init';
|
31
angular/src/styles.scss
Normal file
31
angular/src/styles.scss
Normal file
@ -0,0 +1,31 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
@keyframes donut-spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
:root {
|
||||
--lpx-logo: url('/assets/images/logo/logo-light.png');
|
||||
--lpx-logo-icon: url('/assets/images/logo/logo-light-thumbnail.png');
|
||||
}
|
||||
.donut {
|
||||
display: inline-block;
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #7983ff;
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
animation: donut-spin 1.2s linear infinite;
|
||||
|
||||
&.centered {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
}
|
13
angular/src/test.ts
Normal file
13
angular/src/test.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting,
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
2
angular/start.ps1
Normal file
2
angular/start.ps1
Normal file
@ -0,0 +1,2 @@
|
||||
yarn
|
||||
yarn start
|
15
angular/tsconfig.app.json
Normal file
15
angular/tsconfig.app.json
Normal file
@ -0,0 +1,15 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
32
angular/tsconfig.json
Normal file
32
angular/tsconfig.json
Normal file
@ -0,0 +1,32 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
],
|
||||
"paths": {
|
||||
"@proxy": [
|
||||
"src/app/proxy/index.ts"
|
||||
],
|
||||
"@proxy/*": [
|
||||
"src/app/proxy/*"
|
||||
]
|
||||
},
|
||||
"useDefineForClassFields": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false
|
||||
}
|
||||
}
|
18
angular/tsconfig.spec.json
Normal file
18
angular/tsconfig.spec.json
Normal file
@ -0,0 +1,18 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
8765
angular/yarn.lock
Normal file
8765
angular/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
aspnet-core/.gitattributes
vendored
Normal file
1
aspnet-core/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
**/wwwroot/libs/** linguist-vendored
|
265
aspnet-core/.gitignore
vendored
Normal file
265
aspnet-core/.gitignore
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# BookStore
|
||||
src/Acme.BookStore.Web/Logs/*
|
||||
src/Acme.BookStore.Web.Host/Logs/*
|
||||
src/Acme.BookStore.AuthServer/Logs/*
|
||||
src/Acme.BookStore.HttpApi.Host/Logs/*
|
||||
src/Acme.BookStore.HttpApi.Host/Logs/*
|
||||
src/Acme.BookStore.DbMigrator/Logs/*
|
||||
src/Acme.BookStore.Blazor.Server/Logs/*
|
||||
src/Acme.BookStore.Blazor.Server.Tiered/Logs/*
|
||||
|
||||
# Use abp install-libs to restore.
|
||||
**/wwwroot/libs/*
|
5
aspnet-core/.prettierrc
Normal file
5
aspnet-core/.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"useTabs": false,
|
||||
"tabWidth": 4
|
||||
}
|
123
aspnet-core/Acme.BookStore.sln
Normal file
123
aspnet-core/Acme.BookStore.sln
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29020.237
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain", "src\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj", "{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application", "src\Acme.BookStore.Application\Acme.BookStore.Application.csproj", "{1A94A50E-06DC-43C1-80B5-B662820EC3EB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.EntityFrameworkCore", "src\Acme.BookStore.EntityFrameworkCore\Acme.BookStore.EntityFrameworkCore.csproj", "{C956DD76-69C8-4A9C-83EA-D17DF83340FD}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CA9AC87F-097E-4F15-8393-4BC07735A5B0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{04DBDB01-70F4-4E06-B468-8F87850B22BE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application.Tests", "test\Acme.BookStore.Application.Tests\Acme.BookStore.Application.Tests.csproj", "{50B2631D-129C-47B3-A587-029CCD6099BC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain.Shared", "src\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj", "{42F719ED-8413-4895-B5B4-5AB56079BC66}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application.Contracts", "src\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj", "{520659C8-C734-4298-A3DA-B539DB9DFC0B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi", "src\Acme.BookStore.HttpApi\Acme.BookStore.HttpApi.csproj", "{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi.Client", "src\Acme.BookStore.HttpApi.Client\Acme.BookStore.HttpApi.Client.csproj", "{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.EntityFrameworkCore.Tests", "test\Acme.BookStore.EntityFrameworkCore.Tests\Acme.BookStore.EntityFrameworkCore.Tests.csproj", "{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.TestBase", "test\Acme.BookStore.TestBase\Acme.BookStore.TestBase.csproj", "{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain.Tests", "test\Acme.BookStore.Domain.Tests\Acme.BookStore.Domain.Tests.csproj", "{E512F4D9-9375-480F-A2F6-A46509F9D824}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi.Client.ConsoleTestApp", "test\Acme.BookStore.HttpApi.Client.ConsoleTestApp\Acme.BookStore.HttpApi.Client.ConsoleTestApp.csproj", "{EF480016-9127-4916-8735-D2466BDBC582}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.DbMigrator", "src\Acme.BookStore.DbMigrator\Acme.BookStore.DbMigrator.csproj", "{AA94D832-1CCC-4715-95A9-A483F23A1A5D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.HttpApi.Host", "src\Acme.BookStore.HttpApi.Host\Acme.BookStore.HttpApi.Host.csproj", "{748584B1-BA69-4F6A-81AA-F4BDE6BCE29D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{50B2631D-129C-47B3-A587-029CCD6099BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{50B2631D-129C-47B3-A587-029CCD6099BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50B2631D-129C-47B3-A587-029CCD6099BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50B2631D-129C-47B3-A587-029CCD6099BC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42F719ED-8413-4895-B5B4-5AB56079BC66}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{520659C8-C734-4298-A3DA-B539DB9DFC0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E512F4D9-9375-480F-A2F6-A46509F9D824}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF480016-9127-4916-8735-D2466BDBC582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF480016-9127-4916-8735-D2466BDBC582}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF480016-9127-4916-8735-D2466BDBC582}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF480016-9127-4916-8735-D2466BDBC582}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA94D832-1CCC-4715-95A9-A483F23A1A5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{748584B1-BA69-4F6A-81AA-F4BDE6BCE29D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{748584B1-BA69-4F6A-81AA-F4BDE6BCE29D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{748584B1-BA69-4F6A-81AA-F4BDE6BCE29D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{748584B1-BA69-4F6A-81AA-F4BDE6BCE29D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{554AD327-6DBA-4F8F-96F8-81CE7A0C863F} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{1A94A50E-06DC-43C1-80B5-B662820EC3EB} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{C956DD76-69C8-4A9C-83EA-D17DF83340FD} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{50B2631D-129C-47B3-A587-029CCD6099BC} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
|
||||
{42F719ED-8413-4895-B5B4-5AB56079BC66} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{520659C8-C734-4298-A3DA-B539DB9DFC0B} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{4164BDF7-F527-4E85-9CE6-E3C2D7426A27} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{3B5A0094-670D-4BB1-BFDD-61B88A8773DC} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{1FE30EB9-74A9-47F5-A9F6-7B1FAB672D81} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
|
||||
{91853F21-9CD9-4132-BC29-A7D5D84FFFE7} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
|
||||
{E512F4D9-9375-480F-A2F6-A46509F9D824} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
|
||||
{EF480016-9127-4916-8735-D2466BDBC582} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
|
||||
{AA94D832-1CCC-4715-95A9-A483F23A1A5D} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
{748584B1-BA69-4F6A-81AA-F4BDE6BCE29D} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
23
aspnet-core/Acme.BookStore.sln.DotSettings
Normal file
23
aspnet-core/Acme.BookStore.sln.DotSettings
Normal file
@ -0,0 +1,23 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceDoWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceFixedStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForeachStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceForStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceIfStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceLockStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceUsingStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EnforceWhileStatementBraces/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_REDUNDANT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">False</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQL/@EntryIndexedValue">SQL</s:String>
|
||||
</wpf:ResourceDictionary>
|
5
aspnet-core/NuGet.Config
Normal file
5
aspnet-core/NuGet.Config
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
</packageSources>
|
||||
</configuration>
|
70
aspnet-core/README.md
Normal file
70
aspnet-core/README.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Acme.BookStore
|
||||
|
||||
## About this solution
|
||||
|
||||
This is a layered startup solution based on [Domain Driven Design (DDD)](https://docs.abp.io/en/abp/latest/Domain-Driven-Design) practises. All the fundamental ABP modules are already installed.
|
||||
|
||||
### Pre-requirements
|
||||
|
||||
* [.NET 8.0+ SDK](https://dotnet.microsoft.com/download/dotnet)
|
||||
* [Node v18 or 20](https://nodejs.org/en)
|
||||
|
||||
### Configurations
|
||||
|
||||
The solution comes with a default configuration that works out of the box. However, you may consider to change the following configuration before running your solution:
|
||||
|
||||
* Check the `ConnectionStrings` in `appsettings.json` files under the `Acme.BookStore.HttpApi.Host` and `Acme.BookStore.DbMigrator` projects and change it if you need.
|
||||
|
||||
### Before running the application
|
||||
|
||||
#### Generating a Signing Certificate
|
||||
|
||||
In the production environment, you need to use a production signing certificate. ABP Framework sets up signing and encryption certificates in your application and expects an `openiddict.pfx` file in your application.
|
||||
|
||||
This certificate is already generated by ABP CLI, so most of the time you don't need to generate it yourself. However, if you need to generate a certificate, you can use the following command:
|
||||
|
||||
```bash
|
||||
dotnet dev-certs https -v -ep openiddict.pfx -p 9d3dbfba-a400-4e7c-b7a2-779cd1b0c44f
|
||||
```
|
||||
|
||||
> `9d3dbfba-a400-4e7c-b7a2-779cd1b0c44f` is the password of the certificate, you can change it to any password you want.
|
||||
|
||||
It is recommended to use **two** RSA certificates, distinct from the certificate(s) used for HTTPS: one for encryption, one for signing.
|
||||
|
||||
For more information, please refer to: https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-certificate-recommended-for-production-ready-scenarios
|
||||
|
||||
> Also, see the [Configuring OpenIddict](https://docs.abp.io/en/abp/latest/Deployment/Configuring-OpenIddict#production-environment) documentation for more information.
|
||||
|
||||
#### Install Client-Side Libraries
|
||||
|
||||
Run the following command in the directory of your final application:
|
||||
|
||||
```bash
|
||||
abp install-libs
|
||||
```
|
||||
|
||||
> This command installs all NPM packages for MVC/Razor Pages and Blazor Server UIs and this command is already run by the ABP CLI, so most of the time you don't need to run this command manually.
|
||||
|
||||
#### Create the Database
|
||||
|
||||
Run `Acme.BookStore.DbMigrator` to create the initial database. This should be done in the first run. It is also needed if a new database migration is added to the solution later.
|
||||
|
||||
### Solution structure
|
||||
|
||||
This is a layered monolith application that consists of the following applications:
|
||||
|
||||
* `Acme.BookStore.DbMigrator`: A console application which applies the migrations and also seeds the initial data. It is useful on development as well as on production environment.
|
||||
* `Acme.BookStore.HttpApi.Host`: ASP.NET Core API application that is used to expose the APIs to the clients.
|
||||
* `angular`: Angular application.
|
||||
|
||||
### Deploying the application
|
||||
|
||||
Deploying an ABP application is not different than deploying any .NET or ASP.NET Core application. However, there are some topics that you should care about when you are deploying your applications. You can check ABP's [Deployment documentation](https://docs.abp.io/en/abp/latest/Deployment/Index) before deploying your application.
|
||||
|
||||
### Additional resources
|
||||
|
||||
You can see the following resources to learn more about your solution and the ABP Framework:
|
||||
|
||||
* [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1)
|
||||
* [Application Startup Template Structure](https://docs.abp.io/en/abp/latest/Startup-Templates/Application)
|
||||
* [LeptonX Lite Angular UI](https://docs.abp.io/en/abp/latest/Themes/LeptonXLite/Angular)
|
19
aspnet-core/common.props
Normal file
19
aspnet-core/common.props
Normal file
@ -0,0 +1,19 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.0.0</Version>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<AbpProjectType>app</AbpProjectType>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile">
|
||||
<PropertyGroup>
|
||||
<NoWarn>$(NoWarn);0436</NoWarn>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="$(UserProfile)\.nuget\packages\*\*\contentFiles\any\*\*.abppkg*" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Acme.BookStore</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.ObjectExtending" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.Account.Application.Contracts" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.Identity.Application.Contracts" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.PermissionManagement.Application.Contracts" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.TenantManagement.Application.Contracts" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.FeatureManagement.Application.Contracts" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.SettingManagement.Application.Contracts" Version="8.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Acme.BookStore.Authors
|
||||
{
|
||||
public class AuthorDto : EntityDto<Guid>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public DateTime BirthDate { get; set; }
|
||||
|
||||
public string ShortBio { get; set; }
|
||||
}
|
||||
public class GetAuthorListDto : PagedAndSortedResultRequestDto
|
||||
{
|
||||
public string? Filter { get; set; }
|
||||
}
|
||||
public class CreateAuthorDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(AuthorConsts.MaxNameLength)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public DateTime BirthDate { get; set; }
|
||||
|
||||
public string? ShortBio { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateAuthorDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(AuthorConsts.MaxNameLength)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public DateTime BirthDate { get; set; }
|
||||
|
||||
public string? ShortBio { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace Acme.BookStore.Authors;
|
||||
|
||||
public interface IAuthorAppService : IApplicationService
|
||||
{
|
||||
Task<AuthorDto> GetAsync(Guid id);
|
||||
|
||||
Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input);
|
||||
|
||||
Task<AuthorDto> CreateAsync(CreateAuthorDto input);
|
||||
|
||||
Task UpdateAsync(Guid id, UpdateAuthorDto input);
|
||||
|
||||
Task DeleteAsync(Guid id);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Acme.BookStore.BookIssued
|
||||
{
|
||||
public class BookIssueDto : EntityDto<int>
|
||||
{
|
||||
[Required]
|
||||
public Guid bookId { get; set; }
|
||||
[Required]
|
||||
public int customerId { get; set; }
|
||||
}
|
||||
|
||||
public class BookIssueListDto
|
||||
{
|
||||
public int bookIssueId { get; set; }
|
||||
public string bookName { get; set; }
|
||||
public string customerName { get; set; }
|
||||
public DateTime issueDate { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace Acme.BookStore.BookIssued
|
||||
{
|
||||
public interface IBookIssueAppService : IApplicationService
|
||||
{
|
||||
Task<BookIssueDto> GetAsync(int id);
|
||||
|
||||
Task<PagedResultDto<BookIssueListDto>> GetListAsync();
|
||||
|
||||
Task<BookIssueDto> CreateAsync(BookIssueDto input);
|
||||
|
||||
Task UpdateAsync(int id, BookIssueDto input);
|
||||
|
||||
Task DeleteAsync(int id);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using Volo.Abp.Account;
|
||||
using Volo.Abp.FeatureManagement;
|
||||
using Volo.Abp.Identity;
|
||||
using Volo.Abp.Modularity;
|
||||
using Volo.Abp.ObjectExtending;
|
||||
using Volo.Abp.PermissionManagement;
|
||||
using Volo.Abp.SettingManagement;
|
||||
using Volo.Abp.TenantManagement;
|
||||
|
||||
namespace Acme.BookStore;
|
||||
|
||||
[DependsOn(
|
||||
typeof(BookStoreDomainSharedModule),
|
||||
typeof(AbpAccountApplicationContractsModule),
|
||||
typeof(AbpFeatureManagementApplicationContractsModule),
|
||||
typeof(AbpIdentityApplicationContractsModule),
|
||||
typeof(AbpPermissionManagementApplicationContractsModule),
|
||||
typeof(AbpSettingManagementApplicationContractsModule),
|
||||
typeof(AbpTenantManagementApplicationContractsModule),
|
||||
typeof(AbpObjectExtendingModule)
|
||||
)]
|
||||
public class BookStoreApplicationContractsModule : AbpModule
|
||||
{
|
||||
public override void PreConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
BookStoreDtoExtensions.Configure();
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using Volo.Abp.Identity;
|
||||
using Volo.Abp.ObjectExtending;
|
||||
using Volo.Abp.Threading;
|
||||
|
||||
namespace Acme.BookStore;
|
||||
|
||||
public static class BookStoreDtoExtensions
|
||||
{
|
||||
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
OneTimeRunner.Run(() =>
|
||||
{
|
||||
/* You can add extension properties to DTOs
|
||||
* defined in the depended modules.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ObjectExtensionManager.Instance
|
||||
* .AddOrUpdateProperty<IdentityRoleDto, string>("Title");
|
||||
*
|
||||
* See the documentation for more:
|
||||
* https://docs.abp.io/en/abp/latest/Object-Extensions
|
||||
*/
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Acme.BookStore.Books
|
||||
{
|
||||
public class BookDto : AuditedEntityDto<Guid>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public BookType Type { get; set; }
|
||||
|
||||
public DateTime PublishDate { get; set; }
|
||||
|
||||
public float Price { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
|
||||
namespace Acme.BookStore.Books
|
||||
{
|
||||
public class CreateUpdateBookDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public BookType Type { get; set; } = BookType.Undefined;
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Date)]
|
||||
public DateTime PublishDate { get; set; } = DateTime.Now;
|
||||
|
||||
[Required]
|
||||
public float Price { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace Acme.BookStore.Books
|
||||
{
|
||||
public interface IBookAppService :
|
||||
ICrudAppService< //Defines CRUD methods
|
||||
BookDto, //Used to show books
|
||||
Guid, //Primary key of the book entity
|
||||
PagedAndSortedResultRequestDto, //Used for paging/sorting
|
||||
CreateUpdateBookDto> //Used to create/update a book
|
||||
{
|
||||
Task<List<BookDto>> GetBookDropDown();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Acme.BookStore.Customers
|
||||
{
|
||||
public class CustomerDto : EntityDto<int>
|
||||
{
|
||||
[Required]
|
||||
public string firstName { get; set; }
|
||||
[Required]
|
||||
public string lastName { get; set; }
|
||||
[Required]
|
||||
public string phone { get; set; }
|
||||
[Required]
|
||||
public string address { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
|
||||
namespace Acme.BookStore.Customers
|
||||
{
|
||||
public interface ICustomerAppService : IApplicationService
|
||||
{
|
||||
Task<CustomerDto> GetAsync(int id);
|
||||
|
||||
Task<PagedResultDto<CustomerDto>> GetListAsync();
|
||||
|
||||
Task<CustomerDto> CreateAsync(CustomerDto input);
|
||||
|
||||
Task UpdateAsync(int id, CustomerDto input);
|
||||
|
||||
Task DeleteAsync(int id);
|
||||
Task<List<CustomerDto>> GetcustomerDropDown();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
using Acme.BookStore.Localization;
|
||||
using Volo.Abp.Authorization.Permissions;
|
||||
using Volo.Abp.Localization;
|
||||
|
||||
namespace Acme.BookStore.Permissions;
|
||||
|
||||
public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
|
||||
{
|
||||
public override void Define(IPermissionDefinitionContext context)
|
||||
{
|
||||
var myGroup = context.AddGroup(BookStorePermissions.GroupName);
|
||||
//Define your own permissions here. Example:
|
||||
//myGroup.AddPermission(BookStorePermissions.MyPermission1, L("Permission:MyPermission1"));
|
||||
|
||||
var booksPermission = myGroup.AddPermission(BookStorePermissions.Books.Default, L("Permission:Books"));
|
||||
booksPermission.AddChild(BookStorePermissions.Books.Create, L("Permission:Books.Create"));
|
||||
booksPermission.AddChild(BookStorePermissions.Books.Edit, L("Permission:Books.Edit"));
|
||||
booksPermission.AddChild(BookStorePermissions.Books.Delete, L("Permission:Books.Delete"));
|
||||
|
||||
var authorsPermission = myGroup.AddPermission(
|
||||
BookStorePermissions.Authors.Default, L("Permission:Authors"));
|
||||
authorsPermission.AddChild(
|
||||
BookStorePermissions.Authors.Create, L("Permission:Authors.Create"));
|
||||
authorsPermission.AddChild(
|
||||
BookStorePermissions.Authors.Edit, L("Permission:Authors.Edit"));
|
||||
authorsPermission.AddChild(
|
||||
BookStorePermissions.Authors.Delete, L("Permission:Authors.Delete"));
|
||||
|
||||
var customersPermission = myGroup.AddPermission(
|
||||
BookStorePermissions.Customers.Default, L("Permission:Customers"));
|
||||
customersPermission.AddChild(
|
||||
BookStorePermissions.Customers.Create, L("Permission:Customers.Create"));
|
||||
customersPermission.AddChild(
|
||||
BookStorePermissions.Customers.Edit, L("Permission:Customers.Edit"));
|
||||
customersPermission.AddChild(
|
||||
BookStorePermissions.Customers.Delete, L("Permission:Customers.Delete"));
|
||||
|
||||
var bookissuedPermission = myGroup.AddPermission(
|
||||
BookStorePermissions.BookIssued.Default, L("Permission:BookIssued"));
|
||||
bookissuedPermission.AddChild(
|
||||
BookStorePermissions.BookIssued.Create, L("Permission:BookIssued.Create"));
|
||||
bookissuedPermission.AddChild(
|
||||
BookStorePermissions.BookIssued.Edit, L("Permission:BookIssued.Edit"));
|
||||
bookissuedPermission.AddChild(
|
||||
BookStorePermissions.BookIssued.Delete, L("Permission:BookIssued.Delete"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static LocalizableString L(string name)
|
||||
{
|
||||
return LocalizableString.Create<BookStoreResource>(name);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
namespace Acme.BookStore.Permissions;
|
||||
|
||||
public static class BookStorePermissions
|
||||
{
|
||||
public const string GroupName = "BookStore";
|
||||
|
||||
public static class Books
|
||||
{
|
||||
public const string Default = GroupName + ".Books";
|
||||
public const string Create = Default + ".Create";
|
||||
public const string Edit = Default + ".Edit";
|
||||
public const string Delete = Default + ".Delete";
|
||||
}
|
||||
public static class Authors
|
||||
{
|
||||
public const string Default = GroupName + ".Authors";
|
||||
public const string Create = Default + ".Create";
|
||||
public const string Edit = Default + ".Edit";
|
||||
public const string Delete = Default + ".Delete";
|
||||
}
|
||||
|
||||
public static class Customers
|
||||
{
|
||||
public const string Default = GroupName + ".Customers";
|
||||
public const string Create = Default + ".Create";
|
||||
public const string Edit = Default + ".Edit";
|
||||
public const string Delete = Default + ".Delete";
|
||||
}
|
||||
public static class BookIssued
|
||||
{
|
||||
public const string Default = GroupName + ".BookIssued";
|
||||
public const string Create = Default + ".Create";
|
||||
public const string Edit = Default + ".Edit";
|
||||
public const string Delete = Default + ".Delete";
|
||||
}
|
||||
//Add your own permission names. Example:
|
||||
//public const string MyPermission1 = GroupName + ".MyPermission1";
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Acme.BookStore</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj" />
|
||||
<ProjectReference Include="..\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.Account.Application" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.Identity.Application" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.PermissionManagement.Application" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.TenantManagement.Application" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.FeatureManagement.Application" Version="8.1.3" />
|
||||
<PackageReference Include="Volo.Abp.SettingManagement.Application" Version="8.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Acme.BookStore.Permissions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
|
||||
namespace Acme.BookStore.Authors
|
||||
{
|
||||
|
||||
[Authorize(BookStorePermissions.Authors.Default)]
|
||||
public class AuthorAppService : BookStoreAppService, IAuthorAppService
|
||||
{
|
||||
private readonly IAuthorRepository _authorRepository;
|
||||
private readonly AuthorManager _authorManager;
|
||||
|
||||
public AuthorAppService(
|
||||
IAuthorRepository authorRepository,
|
||||
AuthorManager authorManager)
|
||||
{
|
||||
_authorRepository = authorRepository;
|
||||
_authorManager = authorManager;
|
||||
}
|
||||
|
||||
public async Task<AuthorDto> GetAsync(Guid id)
|
||||
{
|
||||
var author = await _authorRepository.GetAsync(id);
|
||||
return ObjectMapper.Map<Author, AuthorDto>(author);
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input)
|
||||
{
|
||||
if (input.Sorting.IsNullOrWhiteSpace())
|
||||
{
|
||||
input.Sorting = nameof(Author.Name);
|
||||
}
|
||||
|
||||
var authors = await _authorRepository.GetListAsync(
|
||||
input.SkipCount,
|
||||
input.MaxResultCount,
|
||||
input.Sorting,
|
||||
input.Filter
|
||||
);
|
||||
|
||||
var totalCount = input.Filter == null
|
||||
? await _authorRepository.CountAsync()
|
||||
: await _authorRepository.CountAsync(
|
||||
author => author.Name.Contains(input.Filter));
|
||||
|
||||
return new PagedResultDto<AuthorDto>(
|
||||
totalCount,
|
||||
ObjectMapper.Map<List<Author>, List<AuthorDto>>(authors)
|
||||
);
|
||||
}
|
||||
|
||||
[Authorize(BookStorePermissions.Authors.Create)]
|
||||
public async Task<AuthorDto> CreateAsync(CreateAuthorDto input)
|
||||
{
|
||||
var author = await _authorManager.CreateAsync(
|
||||
input.Name,
|
||||
input.BirthDate,
|
||||
input.ShortBio
|
||||
);
|
||||
|
||||
await _authorRepository.InsertAsync(author);
|
||||
|
||||
return ObjectMapper.Map<Author, AuthorDto>(author);
|
||||
}
|
||||
|
||||
[Authorize(BookStorePermissions.Authors.Edit)]
|
||||
public async Task UpdateAsync(Guid id, UpdateAuthorDto input)
|
||||
{
|
||||
var author = await _authorRepository.GetAsync(id);
|
||||
|
||||
if (author.Name != input.Name)
|
||||
{
|
||||
await _authorManager.ChangeNameAsync(author, input.Name);
|
||||
}
|
||||
|
||||
author.BirthDate = input.BirthDate;
|
||||
author.ShortBio = input.ShortBio;
|
||||
|
||||
await _authorRepository.UpdateAsync(author);
|
||||
}
|
||||
|
||||
|
||||
[Authorize(BookStorePermissions.Authors.Delete)]
|
||||
public async Task DeleteAsync(Guid id)
|
||||
{
|
||||
await _authorRepository.DeleteAsync(id);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acme.BookStore.BookIssued;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Acme.BookStore.Permissions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
|
||||
namespace Acme.BookStore.BookIssued
|
||||
{
|
||||
public class BookIssueAppService : BookStoreAppService, IBookIssueAppService
|
||||
{
|
||||
private readonly IBookIssueRepository _bookIssueRepository;
|
||||
private readonly BookIssueManager _bookIssueManager;
|
||||
|
||||
public BookIssueAppService(
|
||||
IBookIssueRepository bookIssueRepository,
|
||||
BookIssueManager bookIssueManager)
|
||||
{
|
||||
_bookIssueRepository = bookIssueRepository;
|
||||
_bookIssueManager = bookIssueManager;
|
||||
}
|
||||
|
||||
public async Task<BookIssueDto> GetAsync(int id)
|
||||
{
|
||||
var cus = await _bookIssueRepository.GetAsync(id);
|
||||
return ObjectMapper.Map<BookIssue, BookIssueDto>(cus);
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<BookIssueListDto>> GetListAsync()
|
||||
{
|
||||
|
||||
var cus = await _bookIssueRepository.BookIssueList();
|
||||
|
||||
return new PagedResultDto<BookIssueListDto>(
|
||||
cus.Count(),
|
||||
ObjectMapper.Map<List<BookIssueList>, List<BookIssueListDto>>(cus)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[Authorize(BookStorePermissions.BookIssued.Create)]
|
||||
|
||||
public async Task<BookIssueDto> CreateAsync(BookIssueDto input)
|
||||
{
|
||||
var cus = ObjectMapper.Map<BookIssueDto, BookIssue>(input);
|
||||
var cust = await _bookIssueManager.CreateAsync(cus);
|
||||
|
||||
var res = await _bookIssueRepository.InsertAsync(cust);
|
||||
|
||||
return ObjectMapper.Map<BookIssue, BookIssueDto>(cust);
|
||||
}
|
||||
|
||||
[Authorize(BookStorePermissions.BookIssued.Edit)]
|
||||
public async Task UpdateAsync(int id, BookIssueDto input)
|
||||
{
|
||||
var cus = await _bookIssueRepository.GetAsync(id);
|
||||
|
||||
await _bookIssueRepository.UpdateAsync(cus);
|
||||
}
|
||||
|
||||
|
||||
[Authorize(BookStorePermissions.BookIssued.Delete)]
|
||||
public async Task DeleteAsync(int id)
|
||||
{
|
||||
await _bookIssueRepository.DeleteAsync(id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Acme.BookStore.Localization;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace Acme.BookStore;
|
||||
|
||||
/* Inherit your application services from this class.
|
||||
*/
|
||||
public abstract class BookStoreAppService : ApplicationService
|
||||
{
|
||||
protected BookStoreAppService()
|
||||
{
|
||||
LocalizationResource = typeof(BookStoreResource);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using AutoMapper;
|
||||
using Acme.BookStore.Books;
|
||||
using Acme.BookStore.Authors;
|
||||
using Acme.BookStore.Customers;
|
||||
using Acme.BookStore.BookIssued;
|
||||
using System.Collections.Generic;
|
||||
namespace Acme.BookStore;
|
||||
public class BookStoreApplicationAutoMapperProfile : Profile
|
||||
{
|
||||
public BookStoreApplicationAutoMapperProfile()
|
||||
{
|
||||
CreateMap<Book, BookDto>();
|
||||
//CreateMap<List<Book>, List<BookDto>>().ReverseMap();
|
||||
CreateMap<CreateUpdateBookDto, Book>();
|
||||
CreateMap<Author, AuthorDto>();
|
||||
CreateMap<Customer, CustomerDto>().ReverseMap();
|
||||
// CreateMap<List<Customer>, List<CustomerDto>>().ReverseMap();
|
||||
CreateMap<BookIssue, BookIssueDto>().ReverseMap();
|
||||
CreateMap<BookIssueList, BookIssueListDto>().ReverseMap();
|
||||
|
||||
/* You can configure your AutoMapper mapping configuration here.
|
||||
* Alternatively, you can split your mapping configurations
|
||||
* into multiple profile classes for a better organization. */
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
using Volo.Abp.Account;
|
||||
using Volo.Abp.AutoMapper;
|
||||
using Volo.Abp.FeatureManagement;
|
||||
using Volo.Abp.Identity;
|
||||
using Volo.Abp.Modularity;
|
||||
using Volo.Abp.PermissionManagement;
|
||||
using Volo.Abp.SettingManagement;
|
||||
using Volo.Abp.TenantManagement;
|
||||
|
||||
namespace Acme.BookStore;
|
||||
|
||||
[DependsOn(
|
||||
typeof(BookStoreDomainModule),
|
||||
typeof(AbpAccountApplicationModule),
|
||||
typeof(BookStoreApplicationContractsModule),
|
||||
typeof(AbpIdentityApplicationModule),
|
||||
typeof(AbpPermissionManagementApplicationModule),
|
||||
typeof(AbpTenantManagementApplicationModule),
|
||||
typeof(AbpFeatureManagementApplicationModule),
|
||||
typeof(AbpSettingManagementApplicationModule)
|
||||
)]
|
||||
public class BookStoreApplicationModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
Configure<AbpAutoMapperOptions>(options =>
|
||||
{
|
||||
options.AddMaps<BookStoreApplicationModule>();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Acme.BookStore.Permissions;
|
||||
|
||||
namespace Acme.BookStore.Books
|
||||
{
|
||||
|
||||
public class BookAppService :
|
||||
CrudAppService<
|
||||
Book, //The Book entity
|
||||
BookDto, //Used to show books
|
||||
Guid, //Primary key of the book entity
|
||||
PagedAndSortedResultRequestDto, //Used for paging/sorting
|
||||
CreateUpdateBookDto>, //Used to create/update a book
|
||||
IBookAppService //implement the IBookAppService
|
||||
{
|
||||
private readonly IRepository<Book, Guid> _bookRepository;
|
||||
public BookAppService(IRepository<Book, Guid> repository)
|
||||
: base(repository)
|
||||
{
|
||||
_bookRepository = repository;
|
||||
GetPolicyName = BookStorePermissions.Books.Default;
|
||||
GetListPolicyName = BookStorePermissions.Books.Default;
|
||||
CreatePolicyName = BookStorePermissions.Books.Create;
|
||||
UpdatePolicyName = BookStorePermissions.Books.Edit;
|
||||
DeletePolicyName = BookStorePermissions.Books.Delete;
|
||||
}
|
||||
|
||||
public async Task<List<BookDto>> GetBookDropDown()
|
||||
{
|
||||
var cus = await _bookRepository.GetListAsync();
|
||||
cus = cus == null ? new List<Book>() : cus;
|
||||
return ObjectMapper.Map<List<Book>, List<BookDto>>(cus);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
using Acme.BookStore.Customers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.ObjectMapping;
|
||||
using Acme.BookStore.Permissions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Acme.BookStore.Customers
|
||||
{
|
||||
public class CustomerAppService: BookStoreAppService, ICustomerAppService
|
||||
{
|
||||
private readonly ICustomerRepository _customerRepository;
|
||||
private readonly CustomerManager _customerManager;
|
||||
|
||||
public CustomerAppService(
|
||||
ICustomerRepository customerRepository,
|
||||
CustomerManager customerManager)
|
||||
{
|
||||
_customerRepository = customerRepository;
|
||||
_customerManager = customerManager;
|
||||
}
|
||||
|
||||
public async Task<CustomerDto> GetAsync(int id)
|
||||
{
|
||||
var cus = await _customerRepository.GetAsync(id);
|
||||
return ObjectMapper.Map<Customer, CustomerDto>(cus);
|
||||
}
|
||||
public async Task<List<CustomerDto>> GetcustomerDropDown()
|
||||
{
|
||||
var cus = await _customerRepository.GetListAsync();
|
||||
cus = cus == null ? new List<Customer>() : cus;
|
||||
return ObjectMapper.Map<List<Customer>, List<CustomerDto>>(cus);
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<CustomerDto>> GetListAsync()
|
||||
{
|
||||
|
||||
var cus = await _customerRepository.GetListAsync();
|
||||
|
||||
return new PagedResultDto<CustomerDto>(
|
||||
cus.Count(),
|
||||
ObjectMapper.Map<List<Customer>, List<CustomerDto>>(cus)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[Authorize(BookStorePermissions.Customers.Create)]
|
||||
|
||||
public async Task<CustomerDto> CreateAsync(CustomerDto input)
|
||||
{
|
||||
var cus = ObjectMapper.Map<CustomerDto,Customer>(input);
|
||||
var cust = await _customerManager.CreateAsync(cus);
|
||||
|
||||
await _customerRepository.InsertAsync(cust);
|
||||
|
||||
return ObjectMapper.Map<Customer, CustomerDto>(cust);
|
||||
}
|
||||
|
||||
[Authorize(BookStorePermissions.Customers.Edit)]
|
||||
|
||||
public async Task UpdateAsync(int id, CustomerDto input)
|
||||
{
|
||||
var cus = await _customerRepository.GetAsync(id);
|
||||
|
||||
if (cus.phone == input.phone)
|
||||
{
|
||||
await _customerManager.ChangeNameAsync(cus, input.firstName,input.lastName);
|
||||
}
|
||||
|
||||
await _customerRepository.UpdateAsync(cus);
|
||||
}
|
||||
|
||||
|
||||
[Authorize(BookStorePermissions.Customers.Delete)]
|
||||
|
||||
public async Task DeleteAsync(int id)
|
||||
{
|
||||
await _customerRepository.DeleteAsync(id);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
[assembly:InternalsVisibleToAttribute("Acme.BookStore.Application.Tests")]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user