Compare commits

...

2 Commits

Author SHA1 Message Date
Christoph Hagen
f956b8b4d2 Protect thumbnail upload, remove unused function 2023-01-15 16:45:27 +01:00
Christoph Hagen
267a71d78c Add function to delete an image 2023-01-15 16:45:07 +01:00
2 changed files with 42 additions and 21 deletions

View File

@ -184,10 +184,10 @@ final class CapServer: ServerOwner {
} }
private func organizeImages() { private func organizeImages() {
caps.values.sorted().forEach(organizeImage) caps.values.sorted().forEach(organizeImages)
} }
private func organizeImage(for cap: Cap) { private func organizeImages(for cap: Cap) {
var cap = cap var cap = cap
guard let images = try? images(in: folder(of: cap.id)) else { guard let images = try? images(in: folder(of: cap.id)) else {
log("Failed to get image urls for cap \(cap.id)") log("Failed to get image urls for cap \(cap.id)")
@ -204,7 +204,7 @@ final class CapServer: ServerOwner {
continue continue
} }
let lastImage = sorted.popLast()! let lastImage = sorted.popLast()!
let newUrl = file(of: cap.id, version: version) let newUrl = imageUrl(of: cap.id, version: version)
do { do {
try fm.moveItem(at: lastImage.url, to: newUrl) try fm.moveItem(at: lastImage.url, to: newUrl)
} catch { } catch {
@ -230,7 +230,7 @@ final class CapServer: ServerOwner {
thumbnailFolder.appendingPathComponent(String(format: "%04d.jpg", cap)) thumbnailFolder.appendingPathComponent(String(format: "%04d.jpg", cap))
} }
func file(of cap: Int, version: Int) -> URL { func imageUrl(of cap: Int, version: Int) -> URL {
folder(of: cap).appendingPathComponent(String(format: "%04d-%02d.jpg", cap, version)) folder(of: cap).appendingPathComponent(String(format: "%04d-%02d.jpg", cap, version))
} }
@ -246,19 +246,6 @@ final class CapServer: ServerOwner {
} }
// MARK: Counts // MARK: Counts
private func updateCounts() throws {
do {
caps = try caps.mapValues {
var cap = $0
cap.count = try count(of: $0.id)
return cap
}
} catch {
log("Failed to update counts: \(error)")
throw error
}
}
private func images(in folder: URL) throws -> [URL] { private func images(in folder: URL) throws -> [URL] {
try fm.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil) try fm.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil)
@ -292,11 +279,11 @@ final class CapServer: ServerOwner {
} }
var id = 0 var id = 0
let capFolder = folder(of: cap) let capFolder = folder(of: cap)
var f = file(of: cap, version: id) var f = imageUrl(of: cap, version: id)
if fm.fileExists(atPath: capFolder.path) { if fm.fileExists(atPath: capFolder.path) {
while fm.fileExists(atPath: f.path) { while fm.fileExists(atPath: f.path) {
id += 1 id += 1
f = file(of: cap, version: id) f = imageUrl(of: cap, version: id)
} }
} else { } else {
try fm.createDirectory(at: capFolder, withIntermediateDirectories: true) try fm.createDirectory(at: capFolder, withIntermediateDirectories: true)
@ -370,7 +357,7 @@ final class CapServer: ServerOwner {
} }
func switchMainImage(to version: Int, for cap: Int) throws { func switchMainImage(to version: Int, for cap: Int) throws {
let file2 = file(of: cap, version: version) let file2 = imageUrl(of: cap, version: version)
guard fm.fileExists(atPath: file2.path) else { guard fm.fileExists(atPath: file2.path) else {
log("No image \(version) for cap \(cap)") log("No image \(version) for cap \(cap)")
throw CapError.invalidFile throw CapError.invalidFile
@ -405,7 +392,7 @@ final class CapServer: ServerOwner {
if cap.name != "" { if cap.name != "" {
updatedCap.name = cap.name updatedCap.name = cap.name
} }
let url = file(of: existingCap.id, version: cap.mainImage) let url = imageUrl(of: existingCap.id, version: cap.mainImage)
if fm.fileExists(atPath: url.path) { if fm.fileExists(atPath: url.path) {
updatedCap.mainImage = cap.mainImage updatedCap.mainImage = cap.mainImage
} }
@ -416,6 +403,20 @@ final class CapServer: ServerOwner {
log("Updated cap \(existingCap.id)") log("Updated cap \(existingCap.id)")
} }
func deleteImage(version: Int, for capId: Int) -> Bool {
guard let cap = caps[capId] else {
return false
}
let url = imageUrl(of: capId, version: version)
guard fm.fileExists(atPath: url.path) else {
return false
}
organizeImages(for: cap)
return true
}
// MARK: Classifier
func updateTrainedClasses(content: String) { func updateTrainedClasses(content: String) {
let trainedCaps = content let trainedCaps = content
.components(separatedBy: "\n") .components(separatedBy: "\n")
@ -440,6 +441,8 @@ final class CapServer: ServerOwner {
log("Updated classifier to version \(version)") log("Updated classifier to version \(version)")
} }
// MARK: Grid
func getListOfMissingThumbnails() -> [Int] { func getListOfMissingThumbnails() -> [Int] {
caps.keys.filter { !fm.fileExists(atPath: thumbnail(of: $0).path) } caps.keys.filter { !fm.fileExists(atPath: thumbnail(of: $0).path) }
} }

View File

@ -84,14 +84,32 @@ func routes(_ app: Application) {
return missingThumbnails.map(String.init).joined(separator: ",") return missingThumbnails.map(String.init).joined(separator: ",")
} }
// Upload the thumbnail of a cap
app.postCatching("thumbnails", ":cap") { request in app.postCatching("thumbnails", ":cap") { request in
guard let cap = request.parameters.get("cap", as: Int.self) else { guard let cap = request.parameters.get("cap", as: Int.self) else {
log("Invalid cap parameter for thumbnail upload") log("Invalid cap parameter for thumbnail upload")
throw Abort(.badRequest) throw Abort(.badRequest)
} }
try authorize(request)
let data = try request.getBodyData() let data = try request.getBodyData()
server.saveThumbnail(data, for: cap) server.saveThumbnail(data, for: cap)
} }
// Delete the image of a cap
app.postCatching("delete", ":cap", ":version") { request in
guard let cap = request.parameters.get("cap", as: Int.self) else {
log("Invalid cap parameter for image deletion")
throw Abort(.badRequest)
}
try authorize(request)
guard let version = request.parameters.get("version", as: Int.self) else {
log("Invalid version parameter for image deletion")
throw Abort(.badRequest)
}
guard server.deleteImage(version: version, for: cap) else {
throw Abort(.gone)
}
}
} }
private extension Request { private extension Request {