finnow/finnow-api/source/attachment/api.d

49 lines
2.1 KiB
D

module attachment.api;
import handy_http_primitives;
import handy_http_data.json;
import handy_http_handlers.path_handler : PathMapping;
import std.conv;
import profile.data;
import profile.data_impl_sqlite;
import profile.service;
import auth.service;
import auth.model;
import util.data;
import attachment.data;
import attachment.model;
/**
* Handles downloading of an attachment. Because the browser is doing the
* downloading instead of a Javascript client, this means we have to embed the
* user's auth token in the query parameters and deal with it differently from
* normal authenticated requests.
* Params:
* request = The HTTP request.
* response = The HTTP response.
*/
@PathMapping(HttpMethod.GET, "/api/profiles/:profile/attachments/:attachmentId/download")
void handleDownloadAttachment(ref ServerHttpRequest request, ref ServerHttpResponse response) {
Optional!AuthContext authCtx = extractAuthContextFromQueryParam(request, response);
if (authCtx.isNull) return;
User user = authCtx.value.user;
string profileName = request.getPathParamOrThrow!string("profile");
ProfileRepository repo = new FileSystemProfileRepository(user.username);
ProfileContext profileCtx = repo.findByName(profileName)
.mapIfPresent!(p => ProfileContext(p, user))
.orElseThrow(() => new HttpStatusException(HttpStatus.NOT_FOUND));
ProfileDataSource ds = getProfileDataSource(profileCtx);
ulong attachmentId = request.getPathParamOrThrow!ulong("attachmentId");
AttachmentRepository attachmentRepo = ds.getAttachmentRepository();
Attachment attachment = attachmentRepo.findById(attachmentId)
.orElseThrow(() => new HttpStatusException(HttpStatus.NOT_FOUND, "Attachment not found."));
ubyte[] content = attachmentRepo.getContent(attachment.id)
.orElseThrow(() => new HttpStatusException(
HttpStatus.INTERNAL_SERVER_ERROR,
"Couldn't get content for attachment."
));
response.headers.add("Content-Disposition", "attachment; filename=\"" ~ attachment.filename ~ "\"");
response.writeBodyBytes(content, attachment.contentType);
}