Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add turbo #75

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions annotations/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ plugins {
}
dependencies {
api("io.micronaut:micronaut-http")
api("io.micronaut.views:micronaut-views-core:5.3.0")
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.micronaut.scheduling.TaskExecutors;
import java.lang.annotation.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import io.micronaut.views.turbo.TurboStreamAction;

@Documented
@Retention(RUNTIME)
Expand All @@ -19,4 +20,6 @@
boolean hidden() default true;

String executesOn() default TaskExecutors.BLOCKING;

String turboView() default "";
}
2 changes: 1 addition & 1 deletion bootstrap/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ plugins {
id("org.projectcheckins.micronaut-modules-conventions")
}
dependencies {
implementation("io.micronaut.views:micronaut-views-fieldset")
implementation("io.micronaut.views:micronaut-views-fieldset:5.3.0")
testImplementation(project(":test-utils"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ dependencies {
implementation("io.micronaut:micronaut-http-server")

// Views
implementation("io.micronaut.views:micronaut-views-fieldset")
implementation("io.micronaut.views:micronaut-views-core")
runtimeOnly("io.micronaut.views:micronaut-views-thymeleaf")
implementation("io.micronaut.views:micronaut-views-fieldset:5.3.0")
implementation("io.micronaut.views:micronaut-views-core:5.3.0")
runtimeOnly("io.micronaut.views:micronaut-views-thymeleaf:5.3.0")

// Test Server
testImplementation("io.micronaut:micronaut-http-server-netty")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ dependencies {
tasks.withType<Test> {
useJUnitPlatform()
}

configurations.all {
resolutionStrategy.eachDependency {
if (requested.group == "io.micronaut.views") {
useVersion("5.3.0")
}
}
}
4 changes: 2 additions & 2 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ dependencies {
api(project(":multitenancy"))
api(project(":security"))
api("io.micronaut.security:micronaut-security")
api("io.micronaut.views:micronaut-views-core")
api("io.micronaut.views:micronaut-views-fieldset")
api("io.micronaut.views:micronaut-views-core:5.3.0")
api("io.micronaut.views:micronaut-views-fieldset:5.3.0")

implementation("com.vladsch.flexmark:flexmark:${project.properties["flexmarkVersion"]}")

Expand Down
1 change: 1 addition & 0 deletions http/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id("org.projectcheckins.micronaut-http-modules-conventions")
}
dependencies {
api(project(":security-http"))
api(project(":core"))
api(project(":bootstrap"))
implementation("io.micronaut:micronaut-management")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.micronaut.views.fields.Form;
import io.micronaut.views.fields.FormGenerator;
import io.micronaut.views.fields.messages.Message;
import io.micronaut.views.turbo.http.TurboMediaType;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
Expand All @@ -28,6 +29,8 @@
import org.projectcheckins.core.forms.*;
import org.projectcheckins.core.services.AnswerService;
import org.projectcheckins.core.services.QuestionService;
import org.projectcheckins.security.http.TurboFrameUtils;
import org.projectcheckins.security.http.TurboStreamUtils;

import java.net.URI;
import java.util.List;
Expand All @@ -39,6 +42,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.projectcheckins.http.controllers.ApiConstants.SLASH;

@Controller
class AnswerController {
private static final String ANSWER = "answer";
Expand Down Expand Up @@ -77,24 +82,30 @@ class AnswerController {
public static final BiFunction<String, String, URI> PATH_SHOW_URI_BUILDER = (questionId, id) -> UriBuilder.of(QuestionController.PATH).path(questionId).path(ANSWER).path(id).path(ApiConstants.ACTION_SHOW).build();
public static final Function<Answer, URI> PATH_SHOW_BUILDER = answer -> PATH_SHOW_URI_BUILDER.apply(answer.questionId(), answer.id());
private static final String VIEW_SHOW = ANSWER + ApiConstants.VIEW_SHOW;
public static final String VIEW_SHOW_FRAGMENT = ANSWER + SLASH + ApiConstants.FRAGMENT_SHOW;

// EDIT
private static final String PATH_EDIT = PATH + ApiConstants.PATH_EDIT;
private static final String VIEW_EDIT = ANSWER + ApiConstants.VIEW_EDIT;
public static final String VIEW_EDIT_FRAGMENT = ANSWER + SLASH + ApiConstants.FRAGMENT_EDIT;
private static final Breadcrumb BREADCRUMB_EDIT = new Breadcrumb(Message.of("Edit Answer", ANSWER + ApiConstants.DOT + ApiConstants.ACTION_EDIT));

private final QuestionService questionService;
private final AnswerService answerService;
private final FormGenerator formGenerator;
private final AnswerSaveFormGenerator answerSaveFormGenerator;

private final HttpLocaleResolver httpLocaleResolver;

AnswerController(QuestionService questionService,
AnswerService answerService,
FormGenerator formGenerator,
AnswerSaveFormGenerator answerSaveFormGenerator,
HttpLocaleResolver httpLocaleResolver) {
this.questionService = questionService;
this.answerService = answerService;
this.formGenerator = formGenerator;
this.answerSaveFormGenerator = answerSaveFormGenerator;
this.httpLocaleResolver = httpLocaleResolver;
}

Expand Down Expand Up @@ -124,21 +135,26 @@ HttpResponse<?> answerShow(HttpRequest<?> request,
@Nullable Tenant tenant) {
Locale locale = httpLocaleResolver.resolveOrDefault(request);
return answerShowModel(questionId, id, authentication, locale, tenant)
.map(model -> new ModelAndView<>(VIEW_SHOW, model))
.map(model -> TurboFrameUtils.turboFrame(request)
.map(frame -> (Object) TurboFrameUtils.turboFrame(frame, VIEW_SHOW_FRAGMENT, model))
.orElseGet(() -> new ModelAndView<>(VIEW_SHOW, model)))
.map(HttpResponse::ok)
.orElseGet(NotFoundController::notFoundRedirect);
}

@GetHtml(uri = PATH_EDIT, rolesAllowed = SecurityRule.IS_AUTHENTICATED)
HttpResponse<?> answerEdit(@NonNull @NotNull HttpRequest<?> request, @PathVariable @NotBlank String questionId,
HttpResponse<?> answerEdit(@NonNull @NotNull HttpRequest<?> request,
@PathVariable @NotBlank String questionId,
@PathVariable @NotBlank String id,
@NonNull Authentication authentication,
@Nullable Locale locale,
@Nullable Tenant tenant) {
return questionService.findById(questionId, tenant)
.flatMap(question -> answerService.findById(id, authentication, tenant)
.map(answer -> updateAnswerModel(question, answer, locale)))
.map(model -> new ModelAndView<>(VIEW_EDIT, model))
.map(model -> TurboFrameUtils.turboFrame(request)
.map(frame -> (Object) TurboFrameUtils.turboFrame(frame, VIEW_EDIT_FRAGMENT, model))
.orElseGet(() -> new ModelAndView<>(VIEW_EDIT, model)))
.map(HttpResponse::ok)
.orElseGet(NotFoundController::notFoundRedirect);
}
Expand All @@ -151,6 +167,12 @@ HttpResponse<?> answerUpdate(@NonNull @NotNull HttpRequest<?> request,
@Nullable Tenant tenant,
@Body @NonNull @NotNull @Valid AnswerUpdateRecord answerUpdate) {
answerService.update(authentication, questionId, id, answerUpdate, tenant);
if (TurboMediaType.acceptsTurboStream(request)) {
return answerShowModel(questionId, id, authentication, httpLocaleResolver.resolveOrDefault(request), tenant)
.flatMap(model -> TurboStreamUtils.turboStream(request, VIEW_SHOW_FRAGMENT, model))
.map(HttpResponse::ok)
.orElseGet(NotFoundController::notFoundRedirect);
}
return HttpResponse.seeOther(PATH_SHOW_URI_BUILDER.apply(questionId, id));
}

Expand All @@ -169,9 +191,10 @@ private Optional<HttpResponse<?>> retrySave(HttpRequest<?> request, Authenticati
return answerForm(request)
.map(f -> questionService.findById(f.questionId(), tenant)
.map(q -> QuestionController.showModel(answerService, q, generateForm(f, ex), auth, tenant))
.map(model -> new ModelAndView<>(QuestionController.VIEW_SHOW, model))
.map(model -> TurboMediaType.acceptsTurboStream(request) ? TurboStreamUtils.turboStream(request, VIEW_SHOW_FRAGMENT, model) : new ModelAndView<>(QuestionController.VIEW_SHOW, model))
.map(b -> HttpResponse.unprocessableEntity().body(b))
.orElseGet(NotFoundController::notFoundRedirect));
.orElseGet(NotFoundController::notFoundRedirect));

}

private Optional<? extends AnswerForm> answerForm(HttpRequest<?> request) {
Expand Down Expand Up @@ -268,6 +291,12 @@ private HttpResponse<?> answerSave(@NonNull HttpRequest<?> request,
return HttpResponse.unprocessableEntity();
}
answerService.save(authentication, new AnswerSave(form.questionId(), form.answerDate(), format, text), tenant);
if (TurboMediaType.acceptsTurboStream(request)) {
return QuestionController.showModel(answerService, questionService, answerSaveFormGenerator, questionId, authentication, tenant)
.flatMap(model -> TurboStreamUtils.turboStream(request, QuestionController.VIEW_SHOW_FRAGMENT, model))
.map(HttpResponse::ok)
.orElseGet(NotFoundController::notFoundRedirect);
}
return HttpResponse.seeOther(QuestionController.PATH_SHOW_BUILDER.apply(questionId));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
)
)
public interface ApiConstants {
String FRAME_ID_MAIN = "main";
String DATA_TURBO_ACTION = "advance";
String PATH_VARIABLE_ID = "{id}";

String SLASH = "/";
Expand All @@ -19,6 +21,10 @@ public interface ApiConstants {
String ACTION_SHOW = "show";

String ACTION_CREATE = "create";
String FRAGMENT_SHOW = "_show.html";
String FRAGMENT_CREATE = "_create.html";
String FRAGMENT_EDIT = "_edit.html";
String FRAGMENT_LIST = "_list.html";
String ACTION_EDIT = "edit";
String ACTION_SAVE = "save";
String ACTION_UPDATE = "update";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ Map<String, Object> index() {
return Collections.emptyMap();
}


public static <T> MutableHttpResponse<T> notFoundRedirect() {
return HttpResponse.seeOther(URI.create(PATH));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.micronaut.views.fields.Form;
import io.micronaut.views.fields.FormGenerator;
import io.micronaut.views.fields.messages.Message;
import io.micronaut.views.turbo.http.TurboMediaType;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.net.URI;
Expand All @@ -25,6 +26,9 @@
import org.projectcheckins.core.api.Profile;
import org.projectcheckins.core.forms.ProfileUpdate;
import org.projectcheckins.core.repositories.ProfileRepository;

import org.projectcheckins.security.http.TurboFrameUtils;
import org.projectcheckins.security.http.TurboStreamUtils;
import static org.projectcheckins.http.controllers.ApiConstants.*;

@Controller
Expand All @@ -36,11 +40,15 @@ class ProfileController {
private static final String MODEL_PROFILE = "profile";

// SHOW
public static final String VIEW_SHOW_FRAGMENT = MODEL_PROFILE + SLASH + ApiConstants.FRAGMENT_SHOW;

private static final Message MESSAGE_SHOW = Message.of("Profile", PROFILE + ApiConstants.DOT + ApiConstants.ACTION_SHOW);
private static final String PATH_SHOW = PATH + SLASH + ApiConstants.ACTION_SHOW;
private static final String VIEW_SHOW = PATH + ApiConstants.VIEW_SHOW;

// EDIT
private static final String VIEW_EDIT_FRAGMENT = PATH + SLASH + FRAGMENT_EDIT;

private static final Message MESSAGE_BREADCRUMB_EDIT = Message.of("Edit", PROFILE + ApiConstants.DOT + ApiConstants.ACTION_EDIT);
private static final Breadcrumb BREADCRUMB_EDIT = new Breadcrumb(MESSAGE_BREADCRUMB_EDIT);
private static final String PATH_EDIT = PATH + SLASH + ApiConstants.ACTION_EDIT;
Expand All @@ -62,7 +70,9 @@ HttpResponse<?> profileShow(@NonNull @NotNull HttpRequest<?> request,
@NonNull @NotNull Authentication authentication,
@Nullable Tenant tenant) {
return showModel(authentication, tenant)
.map(model -> new ModelAndView<>(VIEW_SHOW, model))
.map(model -> TurboFrameUtils.turboFrame(request)
.map(frame -> (Object) TurboFrameUtils.turboFrame(frame, VIEW_SHOW_FRAGMENT, model))
.orElseGet(() -> new ModelAndView<>(VIEW_SHOW, model)))
.map(HttpResponse::ok)
.orElseGet(NotFoundController::notFoundRedirect);
}
Expand All @@ -73,7 +83,9 @@ HttpResponse<?> profileEdit(@NonNull @NotNull HttpRequest<?> request,
@Nullable Tenant tenant) {
return profileRepository.findByAuthentication(authentication, tenant)
.map(this::updateModel)
.map(model -> new ModelAndView<>(VIEW_EDIT, model))
.map(model -> TurboFrameUtils.turboFrame(request)
.map(frame -> (Object) TurboFrameUtils.turboFrame(frame, VIEW_EDIT_FRAGMENT, model))
.orElseGet(() -> new ModelAndView<>(VIEW_EDIT, model)))
.map(HttpResponse::ok)
.orElseGet(NotFoundController::notFoundRedirect);
}
Expand All @@ -85,6 +97,12 @@ HttpResponse<?> profileUpdate(
@NonNull @NotNull @Valid @Body ProfileUpdate profileUpdate,
@Nullable Tenant tenant) {
profileRepository.update(authentication, profileUpdate, tenant);
if (TurboMediaType.acceptsTurboStream(request)) {
return showModel(authentication, tenant)
.flatMap(model -> TurboStreamUtils.turboStream(request, VIEW_SHOW_FRAGMENT, model))
.map(HttpResponse::ok)
.orElseGet(HttpResponse::notFound);
}
return HttpResponse.seeOther(URI.create(PATH_SHOW));
}

Expand Down
Loading
Loading