From f027ee7e39d4662cc48327eb860990a3894756a4 Mon Sep 17 00:00:00 2001 From: u80864958 Date: Mon, 28 Apr 2025 14:25:58 +0200 Subject: [PATCH] update and delete --- backend/blog.db | Bin 20480 -> 20480 bytes backend/blog/controller.go | 24 +++++++++- backend/main.go | 4 +- frontend/src/app/app.routes.ts | 7 ++- .../src/app/routes/admin/admin.component.html | 20 ++++++-- .../src/app/routes/admin/admin.component.ts | 7 ++- .../update-post/update-post.component.html | 10 ++++ .../update-post/update-post.component.spec.ts | 23 +++++++++ .../post/update-post/update-post.component.ts | 45 ++++++++++++++++++ .../src/app/shared/services/posts.service.ts | 17 ++++++- 10 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 frontend/src/app/routes/post/update-post/update-post.component.html create mode 100644 frontend/src/app/routes/post/update-post/update-post.component.spec.ts create mode 100644 frontend/src/app/routes/post/update-post/update-post.component.ts diff --git a/backend/blog.db b/backend/blog.db index 15e0e603abc9a655346eb5fb243a8a3df5301f57..0f85c741270309d3865d6b303f64ab5401f36e76 100644 GIT binary patch literal 20480 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 U9T7!n2o<3qWCTHUzKpxZUmDV>82|tP diff --git a/backend/blog/controller.go b/backend/blog/controller.go index 820829e..adceb86 100644 --- a/backend/blog/controller.go +++ b/backend/blog/controller.go @@ -4,11 +4,13 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "git.schreifuchs.ch/schreifuchs/ng-blog/backend/model" + "github.com/gorilla/mux" ) -func (s Service) CreatePost(w http.ResponseWriter, r *http.Request) { +func (s Service) SavePost(w http.ResponseWriter, r *http.Request) { var post model.Post if err := json.NewDecoder(r.Body).Decode(&post); err != nil { w.WriteHeader(http.StatusBadRequest) @@ -37,3 +39,23 @@ func (s Service) GetAllPosts(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(&posts) w.WriteHeader(http.StatusOK) } + +func (s Service) DeletePost(w http.ResponseWriter, r *http.Request) { + idStr, ok := mux.Vars(r)["postID"] + if !ok { + w.WriteHeader(http.StatusNotFound) + return + } + id, err := strconv.Atoi(idStr) + if err != nil { + w.WriteHeader(http.StatusNotFound) + return + } + + err = s.db.Delete(&model.Post{}, id).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprint(w, err.Error()) + } + w.WriteHeader(http.StatusNoContent) +} diff --git a/backend/main.go b/backend/main.go index 44b89b8..c6bd50b 100644 --- a/backend/main.go +++ b/backend/main.go @@ -30,7 +30,9 @@ func main() { r := mux.NewRouter() r.Use(cors.HandlerForOrigin("*")) r.Handle("/login", auth.Login(user, password, []byte(secret))).Methods("POST") - r.Handle("/posts", auth.Authenticated([]byte(secret))(blg.CreatePost)).Methods("POST") + r.Handle("/posts", auth.Authenticated([]byte(secret))(blg.SavePost)).Methods("POST") + r.Handle("/posts", auth.Authenticated([]byte(secret))(blg.SavePost)).Methods("PUT") + r.Handle("/posts/{postID}", auth.Authenticated([]byte(secret))(blg.DeletePost)).Methods("DELETE") r.Handle("/posts", http.HandlerFunc(blg.GetAllPosts)).Methods("GET") r.Methods("OPTIONS").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // The CORS middleware should set up the headers for you diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index a32cbff..4b95202 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -5,6 +5,7 @@ import { AdminComponent } from './routes/admin/admin.component'; import { LoggedInGuard } from './shared/guards/logged-in.guard'; import { PostEditorComponent } from './components/post-editor/post-editor.component'; import { CreatePostComponent } from './routes/post/create-post/create-post.component'; +import { UpdatePostComponent } from './routes/post/update-post/update-post.component'; export const routes: Routes = [ { path: '', component: HomeComponent }, @@ -12,7 +13,11 @@ export const routes: Routes = [ path: 'post', children: [ { path: 'new', component: CreatePostComponent }, - { path: ':id', component: PostComponent }, + { path: ':id/edit', component: UpdatePostComponent }, + { + path: ':id', + component: PostComponent, + }, ], }, { path: 'admin', component: AdminComponent, canActivate: [LoggedInGuard] }, diff --git a/frontend/src/app/routes/admin/admin.component.html b/frontend/src/app/routes/admin/admin.component.html index 3a12edd..29d1db0 100644 --- a/frontend/src/app/routes/admin/admin.component.html +++ b/frontend/src/app/routes/admin/admin.component.html @@ -12,9 +12,23 @@
-

{{ post.title }}

-

TL;DR; {{ post.tldr }}

+

{{ post.title }}

+

+ TL;DR; {{ post.tldr }} +

+ + Edit + +
diff --git a/frontend/src/app/routes/admin/admin.component.ts b/frontend/src/app/routes/admin/admin.component.ts index 3a0bebe..21256ee 100644 --- a/frontend/src/app/routes/admin/admin.component.ts +++ b/frontend/src/app/routes/admin/admin.component.ts @@ -11,5 +11,10 @@ import { RouterLink, RouterOutlet } from '@angular/router'; templateUrl: './admin.component.html', }) export class AdminComponent { - posts = inject(PostsService).getPosts(); + private postsService = inject(PostsService); + posts = this.postsService.getPosts(); + + delete(id: number) { + this.postsService.deletePost(id); + } } diff --git a/frontend/src/app/routes/post/update-post/update-post.component.html b/frontend/src/app/routes/post/update-post/update-post.component.html new file mode 100644 index 0000000..cebe496 --- /dev/null +++ b/frontend/src/app/routes/post/update-post/update-post.component.html @@ -0,0 +1,10 @@ +
+

Update a Post

+ +
+ diff --git a/frontend/src/app/routes/post/update-post/update-post.component.spec.ts b/frontend/src/app/routes/post/update-post/update-post.component.spec.ts new file mode 100644 index 0000000..46e22f1 --- /dev/null +++ b/frontend/src/app/routes/post/update-post/update-post.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UpdatePostComponent } from './update-post.component'; + +describe('UpdatePostComponent', () => { + let component: UpdatePostComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UpdatePostComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UpdatePostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/routes/post/update-post/update-post.component.ts b/frontend/src/app/routes/post/update-post/update-post.component.ts new file mode 100644 index 0000000..6e1b7e2 --- /dev/null +++ b/frontend/src/app/routes/post/update-post/update-post.component.ts @@ -0,0 +1,45 @@ +import { + Component, + effect, + Input, + OnInit, + signal, + WritableSignal, +} from '@angular/core'; +import { PostsService } from '../../../shared/services/posts.service'; +import { inject } from '@angular/core'; +import { Post } from '../../../shared/interfaces/post'; +import { Location } from '@angular/common'; +import { PostEditorComponent } from '../../../components/post-editor/post-editor.component'; + +@Component({ + selector: 'app-update-post', + imports: [PostEditorComponent], + templateUrl: './update-post.component.html', +}) +export class UpdatePostComponent implements OnInit { + @Input() id!: string; + private postsService = inject(PostsService); + private location = inject(Location); + post: WritableSignal = signal({ + id: 0, + title: '', + tldr: '', + content: '', + }); + + ngOnInit(): void { + const p = this.postsService.getPost(parseInt(this.id))(); + if (p == undefined) { + this.location.back(); + return; + } + + this.post.set(p); + } + + save() { + this.postsService.updatePost(this.post()); + this.location.back(); + } +} diff --git a/frontend/src/app/shared/services/posts.service.ts b/frontend/src/app/shared/services/posts.service.ts index 82f3362..4e56e17 100644 --- a/frontend/src/app/shared/services/posts.service.ts +++ b/frontend/src/app/shared/services/posts.service.ts @@ -1,7 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { computed, - effect, inject, Injectable, Signal, @@ -37,6 +36,15 @@ export class PostsService { return computed(() => this.posts().get(id)); } + deletePost(id: number) { + this.http.delete(`${environment.apiRoot}/posts/${id}`).subscribe(() => { + this.posts.update((p) => { + p.delete(id); + return new Map(p); + }); + }); + } + createPost(post: Post) { this.http .post(`${environment.apiRoot}/posts`, post) @@ -44,4 +52,11 @@ export class PostsService { this.posts.update((p) => new Map(p.set(res.id, res))); }); } + updatePost(post: Post) { + this.http + .put(`${environment.apiRoot}/posts`, post) + .subscribe((res) => { + this.posts.update((p) => new Map(p.set(res.id, res))); + }); + } }