90 lines
2.9 KiB
D
90 lines
2.9 KiB
D
module profile.service;
|
|
|
|
import handy_http_primitives;
|
|
import handy_http_handlers.path_handler;
|
|
|
|
import profile.model;
|
|
import profile.data;
|
|
import profile.data_impl_sqlite;
|
|
import auth.model;
|
|
|
|
/**
|
|
* Validates a profile name.
|
|
* Params:
|
|
* name = The name to check.
|
|
* Returns: True if the profile name is valid.
|
|
*/
|
|
bool validateProfileName(string name) {
|
|
import std.regex;
|
|
import std.uni : toLower;
|
|
if (name is null || name.length < 3) return false;
|
|
auto r = ctRegex!(`^[a-zA-Z]+[a-zA-Z0-9_-]+$`);
|
|
return !matchFirst(name, r).empty;
|
|
}
|
|
|
|
/// Contextual information that's available when handling requests under a profile.
|
|
struct ProfileContext {
|
|
const Profile profile;
|
|
const User user;
|
|
}
|
|
|
|
/**
|
|
* Tries to get a profile context from a request. This will attempt to
|
|
* extract a "profile" path parameter and the authenticated user, and combine
|
|
* them into the ProfileContext.
|
|
* Params:
|
|
* request = The request to read.
|
|
* Returns: An optional profile context.
|
|
*/
|
|
Optional!ProfileContext getProfileContext(in ServerHttpRequest request) {
|
|
import auth.service : AuthContext, getAuthContext;
|
|
foreach (param; getPathParams(request)) {
|
|
if (param.name == "profile") {
|
|
string profileName = param.value;
|
|
if (!validateProfileName(profileName)) return Optional!ProfileContext.empty;
|
|
AuthContext authCtx = getAuthContext(request);
|
|
if (authCtx is null) return Optional!ProfileContext.empty;
|
|
User user = authCtx.user;
|
|
ProfileRepository repo = new FileSystemProfileRepository(user.username);
|
|
return repo.findByName(profileName)
|
|
.mapIfPresent!(p => ProfileContext(p, user));
|
|
}
|
|
}
|
|
return Optional!ProfileContext.empty;
|
|
}
|
|
|
|
/**
|
|
* Similar to `getProfileContext`, but throws an HttpStatusException with a
|
|
* 404 NOT FOUND status if no profile context could be obtained.
|
|
* Params:
|
|
* request = The request to read.
|
|
* Returns: The profile context that was obtained.
|
|
*/
|
|
ProfileContext getProfileContextOrThrow(in ServerHttpRequest request) {
|
|
return getProfileContext(request).orElseThrow(() => new HttpStatusException(HttpStatus.NOT_FOUND));
|
|
}
|
|
|
|
/**
|
|
* Obtains a ProfileDataSource from a ProfileContext. Use this to get access
|
|
* to all profile data when handling an HTTP request, for example.
|
|
* Params:
|
|
* pc = The profile context.
|
|
* Returns: The profile data source.
|
|
*/
|
|
ProfileDataSource getProfileDataSource(in ProfileContext pc) {
|
|
ProfileRepository profileRepo = new FileSystemProfileRepository(pc.user.username);
|
|
return profileRepo.getDataSource(pc.profile);
|
|
}
|
|
|
|
/**
|
|
* Obtains a ProfileDataSource from an HTTP request context. Use this to
|
|
* access all profile data when handling the request.
|
|
* Params:
|
|
* request = The request.
|
|
* Returns: The profile data source.
|
|
*/
|
|
ProfileDataSource getProfileDataSource(in ServerHttpRequest request) {
|
|
ProfileContext pc = getProfileContextOrThrow(request);
|
|
return getProfileDataSource(pc);
|
|
}
|