diff --git a/backend/routers/ImageRouter.ts b/backend/routers/ImageRouter.ts
index 93e94b4..4a55a30 100644
--- a/backend/routers/ImageRouter.ts
+++ b/backend/routers/ImageRouter.ts
@@ -106,7 +106,7 @@ export default class ImageRouter extends AppRouter {
// Clean up request
const req = await convert(rawReq, { name: 'string?', visibility: 'number?' });
- req.name ??= new UUID().toString();
+ req.name ??= rawFile.name;
req.visibility ??= 0;
if (req.visibility < 0 || req.visibility > 2) throw new HttpError("body.visibility: Must be 0, 1, or 2");
const id = new UUID();
@@ -150,6 +150,21 @@ export default class ImageRouter extends AppRouter {
await this.db.images.updateOne({ _id: id }, { $set: { name: body.name, visibility: body.visibility } });
return ImageRouter.deserialize(img);
}
+ @rest('POST', '/delete')
+ async delete(@schema('uuid') id: UUID, @jwt(v => v.salt, true) @auth() jwt: JWTPayload) {
+ const user = await this.db.users.findOne({ username: jwt.name });
+ if (!user) throw new HttpError("You don't exist.");
+
+ const img = await this.db.images.findOne({ _id: id });
+ if (!img) throw new HttpError("Image doesn't exist.");
+ if (user.username !== img.author) throw new HttpError("You don't own the image.");
+
+ await this.db.images.deleteOne({ _id: id });
+ await this.db.users.updateMany({}, {
+ $pull: { images: id, likes: id }
+ });
+ return ImageRouter.deserialize(img);
+ }
@rest('POST', '/like')
async like(@schema('uuid') id: UUID, @jwt(v => v.salt, true) @auth() jwt: JWTPayload) {
diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts
index b32fdaf..84860c8 100644
--- a/frontend/src/app/app-routing.module.ts
+++ b/frontend/src/app/app-routing.module.ts
@@ -5,6 +5,7 @@ import { PageLoginComponent } from './page-login/page-login.component';
import { PageSignupComponent } from './page-signup/page-signup.component';
import { PageUploadComponent } from './page-upload/page-upload.component';
import { PageUserComponent } from './page-user/page-user.component';
+import { PageImageComponent } from './page-image/page-image.component';
const routes: Routes = [
{ path: '', component: PageHomeComponent },
@@ -12,6 +13,7 @@ const routes: Routes = [
{ path: 'signup', component: PageSignupComponent },
{ path: 'upload', component: PageUploadComponent },
{ path: 'user/:name', component: PageUserComponent },
+ { path: 'image/:id', component: PageImageComponent },
];
@NgModule({
diff --git a/frontend/src/app/app.component.scss b/frontend/src/app/app.component.scss
index 9a33dd8..113b9d2 100644
--- a/frontend/src/app/app.component.scss
+++ b/frontend/src/app/app.component.scss
@@ -39,3 +39,24 @@
overflow: hidden;
overflow-y: auto;
}
+
+.overlay {
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 10000000;
+ width: 100vw;
+
+ .messages-container {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ align-items: flex-end;
+ display: inline-block;
+ overflow: hidden;
+ max-height: 100vh;
+ position: absolute;
+ right: 0;
+ }
+}
diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index a38f4d7..f0f3070 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -13,6 +13,7 @@ import { PageUserComponent } from './page-user/page-user.component';
import { ImagesComponent } from './images/images.component';
import { ImageComponent } from './image/image.component';
import { MessageComponent } from './message/message.component';
+import { PageImageComponent } from './page-image/page-image.component';
@NgModule({
declarations: [
@@ -24,7 +25,8 @@ import { MessageComponent } from './message/message.component';
PageUserComponent,
ImagesComponent,
ImageComponent,
- MessageComponent
+ MessageComponent,
+ PageImageComponent
],
imports: [
BrowserModule,
diff --git a/frontend/src/app/image/image.component.html b/frontend/src/app/image/image.component.html
index b58676a..1053136 100644
--- a/frontend/src/app/image/image.component.html
+++ b/frontend/src/app/image/image.component.html
@@ -1,10 +1,13 @@
-
-
{{image.name}}
-
-
-
-
- {{image.likes}}
-
-
By {{image.author}}
+
+
![]()
+
{{image.name}}
+
\ No newline at end of file
diff --git a/frontend/src/app/image/image.component.scss b/frontend/src/app/image/image.component.scss
index 9d8dada..9278663 100644
--- a/frontend/src/app/image/image.component.scss
+++ b/frontend/src/app/image/image.component.scss
@@ -1,12 +1,5 @@
-:host {
+.card {
user-select: none;
-
- .image {
- pointer-events: none;
- height: 15rem;
- display: block;
- }
-
width: min-content;
border-radius: 1rem;
box-shadow: .25rem .25rem 1rem -.5rem #000;
@@ -17,6 +10,12 @@
gap: 1rem;
margin: 1rem;
+ .image {
+ cursor: pointer;
+ height: 15rem;
+ display: block;
+ }
+
.name, .author {
text-align: left;
padding: 0;
@@ -27,11 +26,11 @@
display: flex;
justify-content: space-between;
+ .button {
+ height: 1.5rem;
+ }
.likes {
// flex: 1 0 auto;
- .like {
- height: 1.5rem;
- }
display: inline-flex;
align-items: center;
gap: .5rem;
diff --git a/frontend/src/app/image/image.component.ts b/frontend/src/app/image/image.component.ts
index c5de98c..ccbc804 100644
--- a/frontend/src/app/image/image.component.ts
+++ b/frontend/src/app/image/image.component.ts
@@ -1,6 +1,8 @@
-import { Component, Input } from '@angular/core';
+import { Component, Input, Output } from '@angular/core';
import { environment } from 'src/environments/environment';
import { Image, ImagesService } from '../services/images.service';
+import { MessagesService } from '../services/messages.service';
+import { UsersService } from '../services/users.service';
@Component({
selector: 'app-image',
@@ -11,13 +13,31 @@ export class ImageComponent {
@Input()
public image?: Image | null;
public environment = environment;
+ public deleted = false;
public async like() {
- this.image = await this.images.like(this.image!.id);
+ try {
+ this.image = await this.images.like(this.image!.id);
+ }
+ catch (e: any) { this.msgs.error(e); }
}
public async unlike() {
- this.image = await this.images.unlike(this.image!.id);
+ try {
+ this.image = await this.images.unlike(this.image!.id);
+ }
+ catch (e: any) { this.msgs.error(e); }
+ }
+ public async delete() {
+ try {
+ await this.images.delete(this.image!.id);
+ this.deleted = true;
+ }
+ catch (e: any) { this.msgs.error(e); }
}
- public constructor(public images: ImagesService) {}
+ public constructor(
+ public images: ImagesService,
+ public users: UsersService,
+ private msgs: MessagesService,
+ ) {}
}
diff --git a/frontend/src/app/message/message.component.html b/frontend/src/app/message/message.component.html
index c8c62a6..f223ed2 100644
--- a/frontend/src/app/message/message.component.html
+++ b/frontend/src/app/message/message.component.html
@@ -1,4 +1,4 @@
-
+
{{message.content}}
diff --git a/frontend/src/app/message/message.component.scss b/frontend/src/app/message/message.component.scss
index 9cb0e32..d7c3749 100644
--- a/frontend/src/app/message/message.component.scss
+++ b/frontend/src/app/message/message.component.scss
@@ -1,5 +1,13 @@
.container {
+ width: min-content;
+ background-color: white;
+ box-shadow: .1rem .1rem .5rem -.1rem #000;
+ box-sizing: border-box;
+ display: inline-flex;
+ flex-direction: column;
+ gap: 1rem;
+
padding: .5rem 1rem;
margin: .5rem;
border-bottom-right-radius: 0;
diff --git a/frontend/src/app/page-image/page-image.component.html b/frontend/src/app/page-image/page-image.component.html
new file mode 100644
index 0000000..0592004
--- /dev/null
+++ b/frontend/src/app/page-image/page-image.component.html
@@ -0,0 +1,16 @@
+
+
{{image.name}}
+
![]()
+
+
+
\ No newline at end of file
diff --git a/frontend/src/app/page-image/page-image.component.scss b/frontend/src/app/page-image/page-image.component.scss
new file mode 100644
index 0000000..aefdcef
--- /dev/null
+++ b/frontend/src/app/page-image/page-image.component.scss
@@ -0,0 +1,40 @@
+.container {
+ user-select: none;
+ width: min(100%, 50rem);
+ padding: 1rem;
+ box-sizing: border-box;
+ flex-direction: column;
+ margin: auto;
+
+ .image {
+ margin: 1rem auto;
+ max-height: 30rem;
+ max-width: 100%;
+ display: block;
+ }
+
+ .name, .author {
+ text-align: left;
+ padding: 0;
+ margin: 0;
+ }
+
+ .stats {
+ .actions {
+ display: flex;
+ gap: 1rem;
+ .likes {
+ // flex: 1 0 auto;
+ display: inline-flex;
+ align-items: center;
+ gap: .5rem;
+ }
+ .button {
+ height: 1.5rem;
+ }
+ }
+
+ display: flex;
+ justify-content: space-between;
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/page-image/page-image.component.ts b/frontend/src/app/page-image/page-image.component.ts
new file mode 100644
index 0000000..ea80ff5
--- /dev/null
+++ b/frontend/src/app/page-image/page-image.component.ts
@@ -0,0 +1,53 @@
+import { Component } from '@angular/core';
+import { Image, ImagesService } from '../services/images.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { UsersService } from '../services/users.service';
+import { ScrollService } from '../services/scroll.service';
+import { MessagesService } from '../services/messages.service';
+import { environment } from 'src/environments/environment';
+
+@Component({
+ selector: 'app-page-image',
+ templateUrl: './page-image.component.html',
+ styleUrls: ['./page-image.component.scss']
+})
+export class PageImageComponent {
+ public image?: Image | null;
+ public environment = environment;
+
+ public async like() {
+ try {
+ this.image = await this.images.like(this.image!.id);
+ }
+ catch (e: any) { this.msgs.error(e); }
+ }
+ public async unlike() {
+ try {
+ this.image = await this.images.unlike(this.image!.id);
+ }
+ catch (e: any) { this.msgs.error(e); }
+ }
+ public async delete() {
+ try {
+ await this.images.delete(this.image!.id);
+ this.router.navigateByUrl('/');
+ }
+ catch (e: any) { this.msgs.error(e); }
+ }
+
+ public constructor(
+ route: ActivatedRoute,
+ public users: UsersService,
+ private images: ImagesService,
+ private msgs: MessagesService,
+ private router: Router,
+ ) {
+ route.paramMap.subscribe(async v => {
+ try {
+ this.image = await images.get(v.get('id')!);
+ }
+ catch (e: any) { msgs.error(e); }
+ // this.imagesEl.next();
+ });
+ }
+}
diff --git a/frontend/src/app/services/images.service.ts b/frontend/src/app/services/images.service.ts
index 82b4576..1016a80 100644
--- a/frontend/src/app/services/images.service.ts
+++ b/frontend/src/app/services/images.service.ts
@@ -57,6 +57,9 @@ export class ImagesService {
public async change(id: string, proto: CreateImageBody) {
return await firstValueFrom(this.http.post
(`${this.url}/change?id=${id}`, proto, this.users.httpOptions({})));
}
+ public async delete(id: string) {
+ return await firstValueFrom(this.http.post(`${this.url}/delete?id=${id}`, {}, this.users.httpOptions({})));
+ }
public async like(id: string) {
return await firstValueFrom(this.http.post(`${this.url}/like?id=${id}`, {}, this.users.httpOptions({})));
diff --git a/frontend/src/assets/trash.svg b/frontend/src/assets/trash.svg
new file mode 100644
index 0000000..4e25d5f
--- /dev/null
+++ b/frontend/src/assets/trash.svg
@@ -0,0 +1 @@
+
\ No newline at end of file