Merge pull request #46 from liosha84/34-ann-refresh-cooki-like-as-bezkoder
34 ann refresh cooki like as bezkoder
This commit is contained in:
Binary file not shown.
@@ -1,6 +1,47 @@
|
|||||||
export class Tutorial {
|
export class Tutorial {
|
||||||
|
isSelected?: boolean;
|
||||||
id?: any;
|
id?: any;
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
published?: boolean;
|
published?: boolean;
|
||||||
|
created?: Date;
|
||||||
|
modified?: Date;
|
||||||
|
isEdit?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const TutorialColumns = [
|
||||||
|
{
|
||||||
|
key: 'isSelected',
|
||||||
|
type: 'isSelected',
|
||||||
|
label: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
type: 'text',
|
||||||
|
label: 'Title',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'published',
|
||||||
|
type: 'boolean',
|
||||||
|
label: 'Is Published',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'created',
|
||||||
|
type: 'datetime',
|
||||||
|
label: 'Created Date',
|
||||||
|
required: true,
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'modified',
|
||||||
|
type: 'datetime',
|
||||||
|
label: 'Modified Date',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'isEdit',
|
||||||
|
type: 'isEdit',
|
||||||
|
label: '',
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<mat-card appearance="outlined">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>Edit tutorial</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content >
|
||||||
|
<mat-form-field class="example-full-width">
|
||||||
|
<mat-label>Title</mat-label>
|
||||||
|
<input matInput required
|
||||||
|
[(ngModel)]="tutorial.title">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-tab-group>
|
||||||
|
<mat-tab label="Markdown text">
|
||||||
|
<textarea class="variable-textarea" [(ngModel)]="tutorial.description"></textarea>
|
||||||
|
<markdown class="variable-binding" [data]="tutorial.description"></markdown>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Result">
|
||||||
|
<markdown class="preview" [data]="tutorial.description"></markdown>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Example">
|
||||||
|
<textarea class="variable-textarea" [(ngModel)]="markdown"></textarea>
|
||||||
|
<markdown class="variable-binding" [data]="markdown"></markdown>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
|
||||||
|
<button matButton (click)="updateTutorial()">Save</button>
|
||||||
|
@if (hasError){
|
||||||
|
<mat-error>
|
||||||
|
{{errorMessage}}
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
@if(submitted) {
|
||||||
|
<h4>Tutorial was submitted successfully!</h4>
|
||||||
|
<button matButton routerLink="../tutorial-add">Add new tutorial</button>
|
||||||
|
<button matButton routerLink="../tutorials-list">Back to list</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
.submit-form {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-card{
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
mat-card-title{
|
||||||
|
color: cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-form {
|
||||||
|
min-width: 150px;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.example-full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.variable-binding,
|
||||||
|
.variable-textarea {
|
||||||
|
width: 49%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-textarea {
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,.07);
|
||||||
|
min-height: 420px;
|
||||||
|
padding: 8px;
|
||||||
|
transition: all 300ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-textarea:hover {
|
||||||
|
box-shadow: 0 6px 12px 3px rgba(0,0,0,.09),
|
||||||
|
0 2px 3px 1px rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-binding {
|
||||||
|
display: block;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview {
|
||||||
|
/* display: block;
|
||||||
|
float: right;*/
|
||||||
|
}
|
||||||
|
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TutorialEditComponent } from './tutorial-edit.component';
|
||||||
|
|
||||||
|
describe('TutorialEditComponent', () => {
|
||||||
|
let component: TutorialEditComponent;
|
||||||
|
let fixture: ComponentFixture<TutorialEditComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [TutorialEditComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(TutorialEditComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
|
import {MarkdownComponent} from 'ngx-markdown';
|
||||||
|
import {MatButton} from '@angular/material/button';
|
||||||
|
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||||
|
import {MatError, MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||||
|
import {MatTab, MatTabGroup} from '@angular/material/tabs';
|
||||||
|
import {NgIf} from '@angular/common';
|
||||||
|
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {Tutorial} from '../../models/tutorial.model';
|
||||||
|
import {UserApiService} from '../user-api.service';
|
||||||
|
import {ActivatedRoute, Router, RouterLink} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tutorial-edit.component',
|
||||||
|
imports: [
|
||||||
|
MarkdownComponent,
|
||||||
|
MatButton,
|
||||||
|
MatCard,
|
||||||
|
MatCardActions,
|
||||||
|
MatCardContent,
|
||||||
|
MatCardHeader,
|
||||||
|
MatFormField,
|
||||||
|
MatInput,
|
||||||
|
MatLabel,
|
||||||
|
MatTab,
|
||||||
|
MatTabGroup,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
FormsModule,
|
||||||
|
MatFormField,
|
||||||
|
RouterLink,
|
||||||
|
MatError
|
||||||
|
],
|
||||||
|
templateUrl: './tutorial-edit.component.html',
|
||||||
|
styleUrl: './tutorial-edit.component.scss',
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class TutorialEditComponent {
|
||||||
|
tutorial: Tutorial = new Tutorial();
|
||||||
|
submitted = false;
|
||||||
|
hasError = false;
|
||||||
|
errorMessage = '';
|
||||||
|
markdown = `## Markdown __rulez__!
|
||||||
|
---
|
||||||
|
|
||||||
|
### Syntax highlight
|
||||||
|
\`\`\`typescript
|
||||||
|
const language = 'typescript';
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### Lists
|
||||||
|
1. Ordered list
|
||||||
|
2. Another bullet point
|
||||||
|
- Unordered list
|
||||||
|
- Another unordered bullet
|
||||||
|
|
||||||
|
### Blockquote
|
||||||
|
> Blockquote to the max`;
|
||||||
|
private id: string | null | undefined;
|
||||||
|
|
||||||
|
constructor(private userApiService: UserApiService, private route: ActivatedRoute) {
|
||||||
|
|
||||||
|
this.route.queryParams
|
||||||
|
.subscribe(params => {
|
||||||
|
console.log(params);
|
||||||
|
this.id = params['id'];
|
||||||
|
console.log(this.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.userApiService.getTutorial(this.id).subscribe(
|
||||||
|
data=>{
|
||||||
|
this.tutorial = data;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
updateTutorial(): void {
|
||||||
|
this.userApiService.update(this.id, this.tutorial)
|
||||||
|
.subscribe(
|
||||||
|
response => {
|
||||||
|
console.log(response);
|
||||||
|
this.submitted = true;
|
||||||
|
this.hasError = false;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
this.errorMessage = error.error.message;
|
||||||
|
|
||||||
|
this.hasError = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+145
-26
@@ -1,29 +1,148 @@
|
|||||||
<p>tutorials-list.component works!</p>
|
<article class="table-header">
|
||||||
|
<button
|
||||||
<button mat-raised-button routerLink="../tutorial-add">Add tutorial</button>
|
class="button-remove-rows"
|
||||||
|
mat-button
|
||||||
<mat-list role="list">
|
(click)="removeSelectedRows()"
|
||||||
@for (tutorial of tutorials; track tutorial) {
|
>
|
||||||
<!--
|
Remove Rows
|
||||||
<mat-list-item role="listitem">
|
|
||||||
{{tutorial.title}}
|
|
||||||
|
|
||||||
|
|
||||||
<span class="spacer"></span>
|
|
||||||
<button mat-button>
|
|
||||||
<mat-icon>edit</mat-icon>
|
|
||||||
</button>
|
</button>
|
||||||
<button mat-button>
|
<!--<button class="button-add-row" mat-button (click)="addRow()">
|
||||||
<mat-icon>delete</mat-icon>
|
Add Row
|
||||||
</button>
|
</button>-->
|
||||||
</mat-list-item>-->
|
<button mat-raised-button routerLink="../tutorial-add">Add tutorial</button>
|
||||||
<mat-option >
|
|
||||||
<div style="display:flex; justify-content: space-between">
|
</article>
|
||||||
<span>{{tutorial.title}}</span>
|
<table mat-table [dataSource]="dataSource">
|
||||||
<span></span>
|
@for (column of columnsSchema; track column){
|
||||||
<span (click)="deleteOption($event, tutorial)">X</span>
|
<ng-container [matColumnDef]="column.key">
|
||||||
</div>
|
<th mat-header-cell *matHeaderCellDef>
|
||||||
</mat-option>
|
@switch (column.key) {
|
||||||
|
@case ('isSelected') {
|
||||||
|
<mat-checkbox
|
||||||
|
(change)="selectAll($event)"
|
||||||
|
[checked]="isAllSelected()"
|
||||||
|
[indeterminate]="!isAllSelected() && isAnySelected()"
|
||||||
|
></mat-checkbox>
|
||||||
}
|
}
|
||||||
|
@default {
|
||||||
|
{{ column.label }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<!-- @if (element.isEdit) {-->
|
||||||
|
@switch (column.type) {
|
||||||
|
@case ('isSelected') {
|
||||||
|
<mat-checkbox
|
||||||
|
(change)="element.isSelected = $event.checked"
|
||||||
|
[checked]="element.isSelected"
|
||||||
|
></mat-checkbox>
|
||||||
|
}
|
||||||
|
@case('isEdit') {
|
||||||
|
<div class="btn-edit" >
|
||||||
|
<button mat-button routerLink='../tutorial-edit' [queryParams]="{id:element.id}" (click)="element.isEdit = !element.isEdit">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
class="button-remove"
|
||||||
|
(click)="removeRow(element.id)"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@case ('boolean') {
|
||||||
|
<mat-slide-toggle
|
||||||
|
class="example-margin"
|
||||||
|
[checked]="element[column.key]"
|
||||||
|
[disabled]="true">
|
||||||
|
|
||||||
|
</mat-slide-toggle>
|
||||||
|
}
|
||||||
|
@case ('datetime') {
|
||||||
|
{{ element[column.key] | date: 'medium' }}
|
||||||
|
}
|
||||||
|
@default {
|
||||||
|
{{ element[column.key] }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<!-- }-->
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
}
|
||||||
|
<!--<ng-container [matColumnDef]="col.key" *ngFor="let col of columnsSchema">-->
|
||||||
|
<!--<th mat-header-cell *matHeaderCellDef [ngSwitch]="col.key">
|
||||||
|
<span *ngSwitchCase="'isSelected'">
|
||||||
|
<mat-checkbox
|
||||||
|
(change)="selectAll($event)"
|
||||||
|
[checked]="isAllSelected()"
|
||||||
|
[indeterminate]="!isAllSelected() && isAnySelected()"
|
||||||
|
></mat-checkbox>
|
||||||
|
</span>
|
||||||
|
<span *ngSwitchDefault>{{ col.label }}</span>
|
||||||
|
</th>-->
|
||||||
|
<!-- <mat-form-field-->
|
||||||
|
<!--<td mat-cell *matCellDef="let element">
|
||||||
|
<div [ngSwitch]="col.type" *ngIf="!element.isEdit">
|
||||||
|
<ng-container *ngSwitchCase="'isSelected'">
|
||||||
|
<mat-checkbox
|
||||||
|
(change)="element.isSelected = $event.checked"
|
||||||
|
[checked]="element.isSelected"
|
||||||
|
></mat-checkbox>
|
||||||
|
</ng-container>
|
||||||
|
<div class="btn-edit" *ngSwitchCase="'isEdit'">
|
||||||
|
<button mat-button (click)="element.isEdit = !element.isEdit">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
class="button-remove"
|
||||||
|
(click)="removeRow(element.id)"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<span *ngSwitchCase="'date'">
|
||||||
|
{{ element[col.key] | date: 'mediumDate' }}
|
||||||
|
</span>
|
||||||
|
<span *ngSwitchDefault>
|
||||||
|
{{ element[col.key] }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div [ngSwitch]="col.type" *ngIf="element.isEdit">
|
||||||
|
<div *ngSwitchCase="'isSelected'"></div>
|
||||||
|
<div class="btn-edit" *ngSwitchCase="'isEdit'">
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
(click)="editRow(element)"
|
||||||
|
[disabled]="disableSubmit(element.id)"
|
||||||
|
>
|
||||||
|
Done
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
class="form-input"
|
||||||
|
*ngSwitchCase="'date'"
|
||||||
|
appearance="fill"
|
||||||
|
>
|
||||||
|
<mat-label>Choose a date</mat-label>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
[matDatepicker]="picker"
|
||||||
|
[(ngModel)]="element[col.key]"
|
||||||
|
/>
|
||||||
|
<mat-datepicker-toggle
|
||||||
|
matSuffix
|
||||||
|
[for]="picker"
|
||||||
|
></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</ng-container>-->
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
</mat-list>
|
|
||||||
|
|||||||
+11
@@ -1,3 +1,14 @@
|
|||||||
|
.table-header {
|
||||||
|
width: 90%;
|
||||||
|
margin: auto;
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.spacer{
|
.spacer{
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|||||||
+118
-14
@@ -1,6 +1,6 @@
|
|||||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, OnInit} from '@angular/core';
|
import {Component, CUSTOM_ELEMENTS_SCHEMA, OnInit} from '@angular/core';
|
||||||
import {MatList, MatListItem} from '@angular/material/list';
|
import {MatList, MatListItem} from '@angular/material/list';
|
||||||
import {Tutorial} from '../../models/tutorial.model';
|
import {Tutorial, TutorialColumns} from '../../models/tutorial.model';
|
||||||
import {TutorialService} from '../../services/tutorial.service';
|
import {TutorialService} from '../../services/tutorial.service';
|
||||||
import {UserApiService} from '../user-api.service';
|
import {UserApiService} from '../user-api.service';
|
||||||
import {MatButton} from '@angular/material/button';
|
import {MatButton} from '@angular/material/button';
|
||||||
@@ -11,8 +11,26 @@ import {EventBusService} from '../../_shared/event-bus.service';
|
|||||||
import {EventData} from '../../_shared/event.class';
|
import {EventData} from '../../_shared/event.class';
|
||||||
import {Router, RouterLink} from '@angular/router';
|
import {Router, RouterLink} from '@angular/router';
|
||||||
import {AuthService} from '../../services/auth.service';
|
import {AuthService} from '../../services/auth.service';
|
||||||
|
import {FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {
|
||||||
|
MatCell,
|
||||||
|
MatCellDef,
|
||||||
|
MatColumnDef, MatHeaderCell, MatHeaderCellDef,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatTable,
|
||||||
|
MatTableDataSource
|
||||||
|
} from '@angular/material/table';
|
||||||
|
import {MatFormField, MatInput} from '@angular/material/input';
|
||||||
|
import {DatePipe, NgForOf, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common';
|
||||||
|
import {MatCheckbox} from '@angular/material/checkbox';
|
||||||
|
import {MatDatepicker, MatDatepickerInput, MatDatepickerToggle} from '@angular/material/datepicker';
|
||||||
|
import {MatSlideToggle} from '@angular/material/slide-toggle';
|
||||||
|
|
||||||
@Component({
|
|
||||||
|
@Component({
|
||||||
selector: 'app-tutorials-list.component',
|
selector: 'app-tutorials-list.component',
|
||||||
imports: [
|
imports: [
|
||||||
MatList,
|
MatList,
|
||||||
@@ -21,19 +39,52 @@ import {AuthService} from '../../services/auth.service';
|
|||||||
MatButton,
|
MatButton,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
MatOption,
|
MatOption,
|
||||||
RouterLink
|
RouterLink,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatTable,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatRow,
|
||||||
|
FormsModule,
|
||||||
|
MatInput,
|
||||||
|
MatFormField,
|
||||||
|
MatColumnDef,
|
||||||
|
MatHeaderCell,
|
||||||
|
MatHeaderCellDef,
|
||||||
|
NgSwitch,
|
||||||
|
NgSwitchCase,
|
||||||
|
NgSwitchDefault,
|
||||||
|
MatCellDef,
|
||||||
|
MatCheckbox,
|
||||||
|
MatDatepickerInput,
|
||||||
|
MatDatepickerToggle,
|
||||||
|
MatDatepicker,
|
||||||
|
DatePipe,
|
||||||
|
NgIf,
|
||||||
|
NgForOf,
|
||||||
|
MatCell,
|
||||||
|
MatSlideToggle
|
||||||
],
|
],
|
||||||
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
||||||
templateUrl: './tutorials-list.component.html',
|
templateUrl: './tutorials-list.component.html',
|
||||||
styleUrl: './tutorials-list.component.scss'
|
styleUrl: './tutorials-list.component.scss'
|
||||||
})
|
})
|
||||||
export class TutorialsListComponent implements OnInit {
|
export class TutorialsListComponent implements OnInit {
|
||||||
tutorials?: Tutorial[];
|
//tutorials?: Tutorial[];
|
||||||
|
|
||||||
|
displayedColumns: string[] = TutorialColumns.map((col) => col.key)
|
||||||
|
columnsSchema: any = TutorialColumns
|
||||||
|
dataSource = new MatTableDataSource<Tutorial>()
|
||||||
|
valid: any = {}
|
||||||
|
|
||||||
constructor(private userApiService: UserApiService,
|
constructor(private userApiService: UserApiService,
|
||||||
private storageService: TokenStorageService,
|
private storageService: TokenStorageService,
|
||||||
private eventBusService: EventBusService,
|
private eventBusService: EventBusService,
|
||||||
private router: Router, private authService: AuthService) {
|
private router: Router,
|
||||||
|
private authService: AuthService
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,14 +92,13 @@ export class TutorialsListComponent implements OnInit {
|
|||||||
this.eventBusService.on('logout', () => {
|
this.eventBusService.on('logout', () => {
|
||||||
this.logout();
|
this.logout();
|
||||||
})
|
})
|
||||||
this.retrieveTutorials();
|
this.getTutorials();
|
||||||
}
|
}
|
||||||
|
|
||||||
retrieveTutorials(): void {
|
getTutorials(): void {
|
||||||
this.userApiService.getUserAllTutorials()
|
this.userApiService.getUserAllTutorials()
|
||||||
.subscribe(
|
.subscribe(( data:Tutorial[] ) => {
|
||||||
data => {
|
this.dataSource.data = data;
|
||||||
this.tutorials = data;
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
@@ -65,9 +115,63 @@ export class TutorialsListComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOption($event: MouseEvent, option: any) {
|
selectAll(event: any) {
|
||||||
|
this.dataSource.data = this.dataSource.data.map((item) => ({
|
||||||
|
...item,
|
||||||
|
isSelected: event.checked
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isAllSelected() {
|
||||||
|
return this.dataSource.data.every((item) => item.isSelected)
|
||||||
|
}
|
||||||
|
|
||||||
|
isAnySelected() {
|
||||||
|
return this.dataSource.data.some((item) => item.isSelected)
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSelectedRows() {
|
||||||
|
const selectedTutorials = this.dataSource.data.filter((u: Tutorial) => u.isSelected)
|
||||||
|
/*this.dialog
|
||||||
|
.open(ConfirmDialogComponent)
|
||||||
|
.afterClosed()
|
||||||
|
.subscribe((confirm) => {*/
|
||||||
|
// if (confirm) {
|
||||||
|
this.userApiService.deleteTutorials(selectedTutorials).subscribe(() => {
|
||||||
|
this.dataSource.data = this.dataSource.data.filter(
|
||||||
|
(u: Tutorial) => !u.isSelected
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRow(id: number) {
|
||||||
|
this.userApiService.deleteTutorial(id).subscribe(() => {
|
||||||
|
this.dataSource.data = this.dataSource.data.filter(
|
||||||
|
(u: Tutorial) => u.id !== id,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
editRow(row: Tutorial) {
|
||||||
|
/*if (row.id === 0) {
|
||||||
|
this.userService.addUser(row).subscribe((newUser: User) => {
|
||||||
|
row.id = newUser.id
|
||||||
|
row.isEdit = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.userService.updateUser(row).subscribe(() => (row.isEdit = false))
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
disableSubmit(id: number) {
|
||||||
|
if (this.valid[id]) {
|
||||||
|
return Object.values(this.valid[id]).some((item) => item === false)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
logout(): void {
|
logout(): void {
|
||||||
this.authService.logout().subscribe({
|
this.authService.logout().subscribe({
|
||||||
next: res => {
|
next: res => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {Observable} from 'rxjs';
|
import {forkJoin, Observable} from 'rxjs';
|
||||||
import {Tutorial} from '../models/tutorial.model';
|
import {Tutorial} from '../models/tutorial.model';
|
||||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||||
|
|
||||||
@@ -21,7 +21,28 @@ export class UserApiService {
|
|||||||
return this.http.get<Tutorial[]>(`${this.baseUrl}/tutorials`, this.httpOptions);
|
return this.http.get<Tutorial[]>(`${this.baseUrl}/tutorials`, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTutorial(id: string | null | undefined): Observable<Tutorial> {
|
||||||
|
return this.http.get<Tutorial>(`${this.baseUrl}/tutorial-get/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
create(data: any): Observable<any> {
|
create(data: any): Observable<any> {
|
||||||
return this.http.post(`${this.baseUrl}/tutorial-add`, data);
|
return this.http.post(`${this.baseUrl}/tutorial-add`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update(id: any,data: any): Observable<any> {
|
||||||
|
return this.http.put(`${this.baseUrl}/tutorial-update/${id}`, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTutorials(tutorials: Tutorial[]): Observable<Tutorial[]> {
|
||||||
|
return forkJoin(
|
||||||
|
tutorials.map((tutorial) =>
|
||||||
|
this.http.delete<Tutorial>(`${this.baseUrl}/tutorials/${tutorial.id}`)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTutorial(id: number): Observable<Tutorial> {
|
||||||
|
return this.http.delete<Tutorial>(`${this.baseUrl}/tutorials/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,4 +47,6 @@ mat-sidenav-content{
|
|||||||
}
|
}
|
||||||
.pc-container{
|
.pc-container{
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ const USER_ROUTES: Routes = [
|
|||||||
path: 'tutorial-add',
|
path: 'tutorial-add',
|
||||||
loadComponent: () => import('../user-module/tutorial-add.component/tutorial-add.component').then((c) => c.TutorialAddComponent)
|
loadComponent: () => import('../user-module/tutorial-add.component/tutorial-add.component').then((c) => c.TutorialAddComponent)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'tutorial-edit',
|
||||||
|
loadComponent: () => import('../user-module/tutorial-edit.component/tutorial-edit.component').then((c) => c.TutorialEditComponent)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'ai-models',
|
path: 'ai-models',
|
||||||
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent)
|
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent)
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package com.jambotronGroup.jambotron.ZhiPuAi;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.ai.image.*;
|
||||||
|
import org.springframework.ai.model.ModelOptionsUtils;
|
||||||
|
import org.springframework.ai.retry.RetryUtils;
|
||||||
|
import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
|
||||||
|
import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
|
||||||
|
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MyAIImageModel implements ImageModel {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ZhiPuAiImageModel.class);
|
||||||
|
|
||||||
|
public final RetryTemplate retryTemplate;
|
||||||
|
|
||||||
|
private final MyImageOptions defaultOptions;
|
||||||
|
|
||||||
|
private final ZhiPuAiImageApi zhiPuAiImageApi;
|
||||||
|
|
||||||
|
public MyAIImageModel(ZhiPuAiImageApi zhiPuAiImageApi) {
|
||||||
|
this(zhiPuAiImageApi, MyImageOptions.builder().build(), RetryUtils.DEFAULT_RETRY_TEMPLATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyAIImageModel(ZhiPuAiImageApi zhiPuAiImageApi, MyImageOptions defaultOptions,
|
||||||
|
RetryTemplate retryTemplate) {
|
||||||
|
Assert.notNull(zhiPuAiImageApi, "ZhiPuAiImageApi must not be null");
|
||||||
|
Assert.notNull(defaultOptions, "defaultOptions must not be null");
|
||||||
|
Assert.notNull(retryTemplate, "retryTemplate must not be null");
|
||||||
|
this.zhiPuAiImageApi = zhiPuAiImageApi;
|
||||||
|
this.defaultOptions = defaultOptions;
|
||||||
|
this.retryTemplate = retryTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyImageOptions getDefaultOptions() {
|
||||||
|
return this.defaultOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageResponse call(ImagePrompt imagePrompt) {
|
||||||
|
return this.retryTemplate.execute(ctx -> {
|
||||||
|
|
||||||
|
String instructions = imagePrompt.getInstructions().get(0).getText();
|
||||||
|
|
||||||
|
ZhiPuAiImageApi.ZhiPuAiImageRequest imageRequest = new ZhiPuAiImageApi.ZhiPuAiImageRequest(instructions,
|
||||||
|
ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL);
|
||||||
|
|
||||||
|
if (this.defaultOptions != null) {
|
||||||
|
imageRequest = ModelOptionsUtils.merge(this.defaultOptions, imageRequest,
|
||||||
|
ZhiPuAiImageApi.ZhiPuAiImageRequest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imagePrompt.getOptions() != null) {
|
||||||
|
imageRequest = ModelOptionsUtils.merge(toZhiPuAiImageOptions(imagePrompt.getOptions()), imageRequest,
|
||||||
|
ZhiPuAiImageApi.ZhiPuAiImageRequest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the request
|
||||||
|
ResponseEntity<ZhiPuAiImageApi.ZhiPuAiImageResponse> imageResponseEntity = this.zhiPuAiImageApi
|
||||||
|
.createImage(imageRequest);
|
||||||
|
|
||||||
|
// Convert to org.springframework.ai.model derived ImageResponse data type
|
||||||
|
return convertResponse(imageResponseEntity, imageRequest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImageResponse convertResponse(ResponseEntity<ZhiPuAiImageApi.ZhiPuAiImageResponse> imageResponseEntity,
|
||||||
|
ZhiPuAiImageApi.ZhiPuAiImageRequest zhiPuAiImageRequest) {
|
||||||
|
ZhiPuAiImageApi.ZhiPuAiImageResponse imageApiResponse = imageResponseEntity.getBody();
|
||||||
|
if (imageApiResponse == null) {
|
||||||
|
logger.warn("No image response returned for request: {}", zhiPuAiImageRequest);
|
||||||
|
return new ImageResponse(List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ImageGeneration> imageGenerationList = imageApiResponse.data()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new ImageGeneration(new Image(entry.url(), null)))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return new ImageResponse(imageGenerationList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the {@link ImageOptions} into {@link ZhiPuAiImageOptions}.
|
||||||
|
* @param runtimeImageOptions the image options to use.
|
||||||
|
* @return the converted {@link ZhiPuAiImageOptions}.
|
||||||
|
*/
|
||||||
|
private MyImageOptions toZhiPuAiImageOptions(ImageOptions runtimeImageOptions) {
|
||||||
|
MyImageOptions.Builder myImageOptionsBuilder = MyImageOptions.builder();
|
||||||
|
if (runtimeImageOptions != null) {
|
||||||
|
if (runtimeImageOptions.getModel() != null) {
|
||||||
|
myImageOptionsBuilder.model(runtimeImageOptions.getModel());
|
||||||
|
}
|
||||||
|
if (runtimeImageOptions instanceof MyImageOptions myImageOptions) {
|
||||||
|
if (myImageOptions.getUser() != null) {
|
||||||
|
myImageOptionsBuilder.user(myImageOptions.getUser());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return myImageOptionsBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package com.jambotronGroup.jambotron.ZhiPuAi;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.springframework.ai.image.ImageOptions;
|
||||||
|
import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
|
||||||
|
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class MyImageOptions implements ImageOptions {
|
||||||
|
/**
|
||||||
|
* The model to use for image generation.
|
||||||
|
*/
|
||||||
|
@JsonProperty("model")
|
||||||
|
private String model = ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique identifier representing your end-user, which can help ZhiPuAI to monitor
|
||||||
|
* and detect abuse. User ID length requirement: minimum of 6 characters, maximum of
|
||||||
|
* 128 characters
|
||||||
|
*/
|
||||||
|
@JsonProperty("user_id")
|
||||||
|
private String user;
|
||||||
|
|
||||||
|
public static MyImageOptions.Builder builder() {
|
||||||
|
|
||||||
|
return new MyImageOptions.Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public Integer getN() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getModel() {
|
||||||
|
return this.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public Integer getWidth() {
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public Integer getHeight() {
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public String getResponseFormat() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
|
public String getStyle() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUser() {
|
||||||
|
return this.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(String user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// if (!(o instanceof ZhiPuAiImageOptions that)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// return Objects.equals(this.model, that.model) && Objects.equals(this.user, that.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.model, this.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ZhiPuAiImageOptions{model='" + this.model + '\'' + ", user='" + this.user + '\'' + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
private final MyImageOptions options;
|
||||||
|
|
||||||
|
Builder() {
|
||||||
|
this.options = new MyImageOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyImageOptions.Builder model(String model) {
|
||||||
|
this.options.setModel(model);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyImageOptions.Builder user(String user) {
|
||||||
|
this.options.setUser(user);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyImageOptions build() {
|
||||||
|
|
||||||
|
return this.options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.jambotronGroup.jambotron.ZhiPuAi;
|
package com.jambotronGroup.jambotron.ZhiPuAi;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.ai.image.ImageOptions;
|
||||||
|
import org.springframework.ai.image.ImageOptionsBuilder;
|
||||||
import org.springframework.ai.image.ImagePrompt;
|
import org.springframework.ai.image.ImagePrompt;
|
||||||
import org.springframework.ai.image.ImageResponse;
|
import org.springframework.ai.image.ImageResponse;
|
||||||
|
import org.springframework.ai.retry.RetryUtils;
|
||||||
import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
|
import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
|
||||||
|
import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
|
||||||
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
|
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -21,18 +25,48 @@ public class ZhiPuAiImageService {
|
|||||||
|
|
||||||
private ZhiPuAiImageApi _zhiPuAiImageApi;
|
private ZhiPuAiImageApi _zhiPuAiImageApi;
|
||||||
|
|
||||||
|
private MyAIImageModel _myAIImageModel;
|
||||||
|
|
||||||
private ZhiPuAiImageModel _zhiPuAiImageModel;
|
private ZhiPuAiImageModel _zhiPuAiImageModel;
|
||||||
|
|
||||||
|
private MyImageOptions _myImageOptions;
|
||||||
|
|
||||||
public ZhiPuAiImageService() {
|
public ZhiPuAiImageService() {
|
||||||
|
|
||||||
_zhiPuAiImageApi = new ZhiPuAiImageApi("628447c8c65845a48a7226391464a2ea.Dw8ci6TiW0BRF5LI");
|
_zhiPuAiImageApi = new ZhiPuAiImageApi("628447c8c65845a48a7226391464a2ea.Dw8ci6TiW0BRF5LI");
|
||||||
|
|
||||||
|
ImageOptionsBuilder imageOptionsBuilder = ImageOptionsBuilder.builder();
|
||||||
|
|
||||||
|
ImageOptions imageOptions = imageOptionsBuilder.model("Cogview-3-Flash")//ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL)
|
||||||
|
.height(100)
|
||||||
|
.width(200)
|
||||||
|
|
||||||
|
.build();
|
||||||
|
// _myImageOptions = new MyImageOptions.Builder()
|
||||||
|
// .model(ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL)
|
||||||
|
// .user("jambotron")
|
||||||
|
//
|
||||||
|
// .build();
|
||||||
|
|
||||||
|
|
||||||
_zhiPuAiImageModel = new ZhiPuAiImageModel(_zhiPuAiImageApi);
|
_zhiPuAiImageModel = new ZhiPuAiImageModel(_zhiPuAiImageApi);
|
||||||
|
_myAIImageModel = new MyAIImageModel(_zhiPuAiImageApi);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageResponse generateImage(String prompt) {
|
public ImageResponse generateImage(String prompt) {
|
||||||
|
ImageOptionsBuilder imageOptionsBuilder = ImageOptionsBuilder.builder();
|
||||||
|
ImageOptions imageOptions = imageOptionsBuilder.model("Cogview-3-Flash")//ZhiPuAiImageApi.DEFAULT_IMAGE_MODEL)
|
||||||
|
.height(1440)
|
||||||
|
.width(720)
|
||||||
|
|
||||||
|
.build();
|
||||||
// Create an ImagePrompt object with the desired prompt
|
// Create an ImagePrompt object with the desired prompt
|
||||||
ImagePrompt imagePrompt = new ImagePrompt(prompt);
|
ImagePrompt imagePrompt = new ImagePrompt(prompt,imageOptions);
|
||||||
|
|
||||||
|
/*// Call the generate method to get the image response
|
||||||
|
ImageResponse imageResponse = _myAIImageModel.call(imagePrompt);
|
||||||
|
*/
|
||||||
|
|
||||||
// Call the generate method to get the image response
|
// Call the generate method to get the image response
|
||||||
ImageResponse imageResponse = _zhiPuAiImageModel.call(imagePrompt);
|
ImageResponse imageResponse = _zhiPuAiImageModel.call(imagePrompt);
|
||||||
|
|||||||
@@ -7,21 +7,17 @@ import com.jambotronGroup.jambotron.repository.TutorialRepository;
|
|||||||
import com.jambotronGroup.jambotron.repository.UserRepository;
|
import com.jambotronGroup.jambotron.repository.UserRepository;
|
||||||
import com.jambotronGroup.jambotron.security.AuthenticationFacade;
|
import com.jambotronGroup.jambotron.security.AuthenticationFacade;
|
||||||
import com.jambotronGroup.jambotron.security.services.UserDetailsImpl;
|
import com.jambotronGroup.jambotron.security.services.UserDetailsImpl;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.sql.Timestamp;
|
||||||
import java.util.List;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Optional;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600, allowCredentials="true")
|
//@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600, allowCredentials="true")
|
||||||
@@ -106,17 +102,6 @@ public class TutorialController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/tutorials/{id}")
|
|
||||||
public ResponseEntity<Tutorial> getTutorialById(@PathVariable("id") long id) {
|
|
||||||
Optional<Tutorial> tutorialData = tutorialRepository.findById(id);
|
|
||||||
|
|
||||||
if (tutorialData.isPresent()) {
|
|
||||||
return new ResponseEntity<>(tutorialData.get(), HttpStatus.OK);
|
|
||||||
} else {
|
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("user/tutorial-add")
|
@PostMapping("user/tutorial-add")
|
||||||
public ResponseEntity<Tutorial> createTutorial(@RequestBody Tutorial tutorial) {
|
public ResponseEntity<Tutorial> createTutorial(@RequestBody Tutorial tutorial) {
|
||||||
|
|
||||||
@@ -127,29 +112,49 @@ public class TutorialController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Tutorial _tutorial = tutorialRepository
|
Tutorial _tutorial = tutorialRepository
|
||||||
.save(new Tutorial(tutorial.getTitle(), tutorial.getDescription(), false, user));
|
.save(new Tutorial(tutorial.getTitle(), tutorial.getDescription(), false, user, Timestamp.valueOf(LocalDateTime.now()), Timestamp.valueOf(LocalDateTime.now())));
|
||||||
return new ResponseEntity<>(_tutorial, HttpStatus.CREATED);
|
return new ResponseEntity<>(_tutorial, HttpStatus.CREATED);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
|
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/tutorials/{id}")
|
@GetMapping("user/tutorial-get/{id}")
|
||||||
public ResponseEntity<Tutorial> updateTutorial(@PathVariable("id") long id, @RequestBody Tutorial tutorial) {
|
public ResponseEntity<Tutorial> getTutorial(@PathVariable("id") long id) {
|
||||||
Optional<Tutorial> tutorialData = tutorialRepository.findById(id);
|
Optional<Tutorial> tutorialData = tutorialRepository.findById(id);
|
||||||
|
|
||||||
if (tutorialData.isPresent()) {
|
if (tutorialData.isPresent()) {
|
||||||
Tutorial _tutorial = tutorialData.get();
|
|
||||||
_tutorial.setTitle(tutorial.getTitle());
|
return new ResponseEntity<Tutorial>(tutorialData.get(), HttpStatus.OK);
|
||||||
_tutorial.setDescription(tutorial.getDescription());
|
|
||||||
_tutorial.setPublished(tutorial.isPublished());
|
|
||||||
return new ResponseEntity<>(tutorialRepository.save(_tutorial), HttpStatus.OK);
|
|
||||||
} else {
|
} else {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/tutorials/{id}")
|
@PutMapping("user/tutorial-update/{id}")
|
||||||
|
public ResponseEntity<?> updateTutorial(@PathVariable("id") long id, @RequestBody Tutorial tutorial) {
|
||||||
|
Optional<Tutorial> tutorialData = tutorialRepository.findById(id);
|
||||||
|
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||||
|
if (tutorialData.isPresent()) {
|
||||||
|
Tutorial servTutorial = tutorialData.get();
|
||||||
|
servTutorial.setTitle(tutorial.getTitle());
|
||||||
|
servTutorial.setDescription(tutorial.getDescription());
|
||||||
|
servTutorial.setPublished(tutorial.isPublished());
|
||||||
|
try {
|
||||||
|
servTutorial = tutorialRepository.save(servTutorial);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
map.put("status", 0);
|
||||||
|
map.put("message", e.getMessage());
|
||||||
|
return new ResponseEntity<>(map,HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(servTutorial, HttpStatus.OK);
|
||||||
|
} else {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("user/tutorials/{id}")
|
||||||
public ResponseEntity<HttpStatus> deleteTutorial(@PathVariable("id") long id) {
|
public ResponseEntity<HttpStatus> deleteTutorial(@PathVariable("id") long id) {
|
||||||
try {
|
try {
|
||||||
tutorialRepository.deleteById(id);
|
tutorialRepository.deleteById(id);
|
||||||
|
|||||||
@@ -25,15 +25,25 @@ public class Tutorial {
|
|||||||
@JoinColumn(name = "userID", nullable = false)
|
@JoinColumn(name = "userID", nullable = false)
|
||||||
private User user;
|
private User user;
|
||||||
|
|
||||||
|
@Column(name = "created")
|
||||||
|
private java.sql.Timestamp created;
|
||||||
|
|
||||||
|
@Column(name = "modified")
|
||||||
|
private java.sql.Timestamp modified;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public Tutorial() {
|
public Tutorial() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tutorial(String title, String description, boolean published, User user) {
|
public Tutorial(String title, String description, boolean published, User user, java.sql.Timestamp created, java.sql.Timestamp modified) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.published = published;
|
this.published = published;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
this.created = created;
|
||||||
|
this.modified = modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
@@ -64,6 +74,22 @@ public class Tutorial {
|
|||||||
this.published = isPublished;
|
this.published = isPublished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCreated(java.sql.Timestamp created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.sql.Timestamp getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModified(java.sql.Timestamp modified) {
|
||||||
|
this.modified = modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.sql.Timestamp getModified() {
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
|
return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.jambotronGroup.jambotron.utils;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
public class DateTimeHelper {
|
||||||
|
|
||||||
|
public static SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public static java.sql.Timestamp parseTimestamp(String timestamp) {
|
||||||
|
try {
|
||||||
|
return new Timestamp(DATE_TIME_FORMAT.parse(timestamp).getTime());
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new IllegalArgumentException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,32 +2,32 @@ spring.application.name=jambotron
|
|||||||
|
|
||||||
#============Localhost Configurations========================
|
#============Localhost Configurations========================
|
||||||
|
|
||||||
#spring.datasource.url= jdbc:postgresql://localhost:5432/jambotronDB
|
spring.datasource.url= jdbc:postgresql://localhost:5432/jambotronDB
|
||||||
#spring.datasource.username= admin
|
spring.datasource.username= admin
|
||||||
#spring.datasource.password= postgrespw
|
spring.datasource.password= postgrespw
|
||||||
|
|
||||||
#spring.flyway.baseline-on-migrate=true
|
|
||||||
#spring.flyway.validate-on-migrate=true
|
|
||||||
#
|
|
||||||
#spring.flyway.url=jdbc:postgresql://localhost:5432/jambotronDB
|
|
||||||
#spring.flyway.user=admin
|
|
||||||
#spring.flyway.password=postgrespw
|
|
||||||
|
|
||||||
|
|
||||||
#============Koyeb Configurations========================
|
|
||||||
|
|
||||||
spring.datasource.url= jdbc:postgresql://ep-red-breeze-a2cxhq5f.eu-central-1.pg.koyeb.app/jambotronDB
|
|
||||||
spring.datasource.username= koyeb-adm
|
|
||||||
spring.datasource.password= npg_HfFEUA7bay1i
|
|
||||||
|
|
||||||
spring.flyway.baseline-on-migrate=true
|
spring.flyway.baseline-on-migrate=true
|
||||||
spring.flyway.validate-on-migrate=true
|
spring.flyway.validate-on-migrate=true
|
||||||
|
|
||||||
spring.flyway.url=jdbc:postgresql://ep-red-breeze-a2cxhq5f.eu-central-1.pg.koyeb.app/jambotronDB
|
spring.flyway.url=jdbc:postgresql://localhost:5432/jambotronDB
|
||||||
spring.flyway.user=koyeb-adm
|
spring.flyway.user=admin
|
||||||
spring.flyway.password=npg_HfFEUA7bay1i
|
spring.flyway.password=postgrespw
|
||||||
|
|
||||||
|
|
||||||
|
#============Koyeb Configurations========================
|
||||||
|
|
||||||
|
#spring.datasource.url= jdbc:postgresql://ep-red-breeze-a2cxhq5f.eu-central-1.pg.koyeb.app/jambotronDB
|
||||||
|
#spring.datasource.username= koyeb-adm
|
||||||
|
#spring.datasource.password= npg_HfFEUA7bay1i
|
||||||
|
#
|
||||||
|
#spring.flyway.baseline-on-migrate=true
|
||||||
|
#spring.flyway.validate-on-migrate=true
|
||||||
|
#
|
||||||
|
#spring.flyway.url=jdbc:postgresql://ep-red-breeze-a2cxhq5f.eu-central-1.pg.koyeb.app/jambotronDB
|
||||||
|
#spring.flyway.user=koyeb-adm
|
||||||
|
#spring.flyway.password=npg_HfFEUA7bay1i
|
||||||
|
#
|
||||||
|
|
||||||
#spring.datasource.url=${SPRING_DATASOURCE_URL}
|
#spring.datasource.url=${SPRING_DATASOURCE_URL}
|
||||||
#spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
|
#spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
|
||||||
#spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
|
#spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
DROP TABLE tutorials;
|
||||||
|
|
||||||
|
CREATE TABLE tutorials
|
||||||
|
(
|
||||||
|
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
|
||||||
|
published boolean,
|
||||||
|
title character varying(255) COLLATE pg_catalog."default",
|
||||||
|
userid bigint,
|
||||||
|
created timestamp with time zone,
|
||||||
|
modified timestamp with time zone,
|
||||||
|
description character varying(255) COLLATE pg_catalog."default",
|
||||||
|
CONSTRAINT tutorials_title_key UNIQUE (title),
|
||||||
|
CONSTRAINT "tutorial_user_FK" FOREIGN KEY (userid)
|
||||||
|
REFERENCES public.users (id) MATCH SIMPLE
|
||||||
|
ON UPDATE NO ACTION
|
||||||
|
ON DELETE NO ACTION
|
||||||
|
)
|
||||||
|
|
||||||
Reference in New Issue
Block a user