Skip to content

Commit 85ab74a

Browse files
authored
Make activity logs read like community posts
Merged after passing CI and OpenAPI drift checks.
2 parents f12e139 + 1793b2d commit 85ab74a

13 files changed

Lines changed: 801 additions & 181 deletions

File tree

backend/openapi.json

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
"title": "OpenAPI definition",
55
"version": "v0"
66
},
7+
"servers": [
8+
{
9+
"url": "http://localhost:8080",
10+
"description": "Generated server url"
11+
}
12+
],
713
"paths": {
814
"/api/team-randomizer/rooms/{roomId}": {
915
"get": {
@@ -1750,14 +1756,18 @@
17501756
"schema": {
17511757
"type": "object",
17521758
"properties": {
1759+
"files": {
1760+
"type": "array",
1761+
"items": {
1762+
"type": "string",
1763+
"format": "binary"
1764+
}
1765+
},
17531766
"file": {
17541767
"type": "string",
17551768
"format": "binary"
17561769
}
1757-
},
1758-
"required": [
1759-
"file"
1760-
]
1770+
}
17611771
}
17621772
}
17631773
}
@@ -4845,6 +4855,56 @@
48454855
}
48464856
}
48474857
},
4858+
"/api/club-events/{id}/entries/{entryId}/files/{fileId}/download": {
4859+
"get": {
4860+
"tags": [
4861+
"club-event-controller"
4862+
],
4863+
"operationId": "downloadEntryFile",
4864+
"parameters": [
4865+
{
4866+
"name": "id",
4867+
"in": "path",
4868+
"required": true,
4869+
"schema": {
4870+
"type": "integer",
4871+
"format": "int64"
4872+
}
4873+
},
4874+
{
4875+
"name": "entryId",
4876+
"in": "path",
4877+
"required": true,
4878+
"schema": {
4879+
"type": "integer",
4880+
"format": "int64"
4881+
}
4882+
},
4883+
{
4884+
"name": "fileId",
4885+
"in": "path",
4886+
"required": true,
4887+
"schema": {
4888+
"type": "integer",
4889+
"format": "int64"
4890+
}
4891+
}
4892+
],
4893+
"responses": {
4894+
"200": {
4895+
"description": "OK",
4896+
"content": {
4897+
"*/*": {
4898+
"schema": {
4899+
"type": "string",
4900+
"format": "binary"
4901+
}
4902+
}
4903+
}
4904+
}
4905+
}
4906+
}
4907+
},
48484908
"/api/club-events/{id}/entries/{entryId}/download": {
48494909
"get": {
48504910
"tags": [
@@ -6879,6 +6939,12 @@
68796939
"type": "integer",
68806940
"format": "int64"
68816941
},
6942+
"files": {
6943+
"type": "array",
6944+
"items": {
6945+
"$ref": "#/components/schemas/EntryFile"
6946+
}
6947+
},
68826948
"voteCount": {
68836949
"type": "integer",
68846950
"format": "int64"
@@ -6896,6 +6962,28 @@
68966962
}
68976963
}
68986964
},
6965+
"EntryFile": {
6966+
"type": "object",
6967+
"properties": {
6968+
"id": {
6969+
"type": "integer",
6970+
"format": "int64"
6971+
},
6972+
"downloadUrl": {
6973+
"type": "string"
6974+
},
6975+
"originalName": {
6976+
"type": "string"
6977+
},
6978+
"mimeType": {
6979+
"type": "string"
6980+
},
6981+
"fileSize": {
6982+
"type": "integer",
6983+
"format": "int64"
6984+
}
6985+
}
6986+
},
68996987
"ClubEventVoteRequest": {
69006988
"type": "object",
69016989
"properties": {

backend/src/main/java/com/coms/backend/controller/ClubEventController.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.coms.backend.controller;
22

33
import com.coms.backend.domain.ClubEventEntry;
4+
import com.coms.backend.domain.ClubEventEntryFile;
45
import com.coms.backend.dto.ClubEventRequest;
56
import com.coms.backend.dto.ClubEventResponse;
67
import com.coms.backend.dto.ClubEventVoteRequest;
@@ -67,9 +68,13 @@ public ResponseEntity<ClubEventResponse.Entry> addEntry(@PathVariable Long id,
6768
@RequestParam("title") String title,
6869
@RequestParam(value = "authorName", required = false) String authorName,
6970
@RequestParam(value = "description", required = false) String description,
70-
@RequestParam("file") MultipartFile file,
71+
@RequestParam(value = "files", required = false) List<MultipartFile> files,
72+
@RequestParam(value = "file", required = false) MultipartFile legacyFile,
7173
Authentication authentication) {
72-
return ResponseEntity.ok(clubEventService.addEntry(id, title, authorName, description, file, authentication.getName()));
74+
List<MultipartFile> uploadFiles = files == null || files.isEmpty()
75+
? (legacyFile == null ? List.of() : List.of(legacyFile))
76+
: files;
77+
return ResponseEntity.ok(clubEventService.addEntry(id, title, authorName, description, uploadFiles, authentication.getName()));
7378
}
7479

7580
@PostMapping("/{id}/entries/{entryId}/vote")
@@ -92,6 +97,19 @@ public ResponseEntity<Resource> downloadEntry(@PathVariable Long id, @PathVariab
9297
.body(resource);
9398
}
9499

100+
@GetMapping("/{id}/entries/{entryId}/files/{fileId}/download")
101+
public ResponseEntity<Resource> downloadEntryFile(@PathVariable Long id,
102+
@PathVariable Long entryId,
103+
@PathVariable Long fileId) {
104+
ClubEventEntryFile meta = clubEventService.loadEntryFileMeta(id, entryId, fileId);
105+
Resource resource = clubEventService.loadEntryFileResource(id, entryId, fileId);
106+
return ResponseEntity.ok()
107+
.contentType(mediaType(meta.getMimeType()))
108+
.header(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
109+
.filename(meta.getOriginalName(), StandardCharsets.UTF_8).build().toString())
110+
.body(resource);
111+
}
112+
95113
@DeleteMapping("/{id}/entries/{entryId}")
96114
public ResponseEntity<Void> deleteEntry(@PathVariable Long id, @PathVariable Long entryId) {
97115
clubEventService.deleteEntry(id, entryId);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.coms.backend.domain;
2+
3+
import jakarta.persistence.*;
4+
5+
@Entity
6+
@Table(name = "club_event_entry_files")
7+
public class ClubEventEntryFile {
8+
9+
@Id
10+
@GeneratedValue(strategy = GenerationType.IDENTITY)
11+
private Long id;
12+
13+
@Column(name = "entry_id", nullable = false)
14+
private Long entryId;
15+
16+
@Column(name = "stored_name", nullable = false, length = 255)
17+
private String storedName;
18+
19+
@Column(name = "original_name", nullable = false, length = 255)
20+
private String originalName;
21+
22+
@Column(name = "mime_type", nullable = false, length = 100)
23+
private String mimeType;
24+
25+
@Column(name = "file_size", nullable = false)
26+
private long fileSize;
27+
28+
@Column(nullable = false)
29+
private int position;
30+
31+
public ClubEventEntryFile() {}
32+
33+
public ClubEventEntryFile(Long entryId, String storedName, String originalName, String mimeType, long fileSize, int position) {
34+
this.entryId = entryId;
35+
this.storedName = storedName;
36+
this.originalName = originalName;
37+
this.mimeType = mimeType;
38+
this.fileSize = fileSize;
39+
this.position = position;
40+
}
41+
42+
public Long getId() { return id; }
43+
public Long getEntryId() { return entryId; }
44+
public String getStoredName() { return storedName; }
45+
public String getOriginalName() { return originalName; }
46+
public String getMimeType() { return mimeType; }
47+
public long getFileSize() { return fileSize; }
48+
public int getPosition() { return position; }
49+
}

backend/src/main/java/com/coms/backend/dto/ClubEventResponse.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,18 @@ public record Entry(
2727
String originalName,
2828
String mimeType,
2929
long fileSize,
30+
List<EntryFile> files,
3031
long voteCount,
3132
boolean myVote,
3233
int rank,
3334
LocalDateTime createdAt
3435
) {}
36+
37+
public record EntryFile(
38+
Long id,
39+
String downloadUrl,
40+
String originalName,
41+
String mimeType,
42+
long fileSize
43+
) {}
3544
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.coms.backend.repository;
2+
3+
import com.coms.backend.domain.ClubEventEntryFile;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Collection;
7+
import java.util.List;
8+
9+
public interface ClubEventEntryFileRepository extends JpaRepository<ClubEventEntryFile, Long> {
10+
List<ClubEventEntryFile> findByEntryIdOrderByPositionAsc(Long entryId);
11+
List<ClubEventEntryFile> findByEntryIdInOrderByPositionAsc(Collection<Long> entryIds);
12+
void deleteByEntryId(Long entryId);
13+
void deleteByEntryIdIn(Collection<Long> entryIds);
14+
}

0 commit comments

Comments
 (0)