package org.iatoki.judgels.uriel.controllers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.iatoki.judgels.play.IdentityUtils;
import org.iatoki.judgels.play.InternalLink;
import org.iatoki.judgels.play.LazyHtml;
import org.iatoki.judgels.play.Page;
import org.iatoki.judgels.play.controllers.AbstractJudgelsController;
import org.iatoki.judgels.play.views.html.layouts.subtabLayout;
import org.iatoki.judgels.play.views.html.layouts.heading3Layout;
import org.iatoki.judgels.play.views.html.layouts.messageView;
import org.iatoki.judgels.jophiel.Jophiel;
import org.iatoki.judgels.uriel.Contest;
import org.iatoki.judgels.uriel.ContestContestant;
import org.iatoki.judgels.uriel.ContestPermissions;
import org.iatoki.judgels.uriel.forms.ContestContestantCreateForm;
import org.iatoki.judgels.uriel.ContestContestantNotFoundException;
import org.iatoki.judgels.uriel.ContestContestantStatus;
import org.iatoki.judgels.uriel.forms.ContestContestantUpdateForm;
import org.iatoki.judgels.uriel.forms.ContestContestantUploadForm;
import org.iatoki.judgels.uriel.ContestNotFoundException;
import org.iatoki.judgels.uriel.services.ContestContestantService;
import org.iatoki.judgels.uriel.services.ContestContestantPasswordService;
import org.iatoki.judgels.uriel.services.ContestService;
import org.iatoki.judgels.uriel.UploadResult;
import org.iatoki.judgels.uriel.services.ContestSupervisorService;
import org.iatoki.judgels.uriel.services.UserService;
import org.iatoki.judgels.uriel.controllers.securities.Authenticated;
import org.iatoki.judgels.uriel.controllers.securities.HasRole;
import org.iatoki.judgels.uriel.controllers.securities.LoggedIn;
import org.iatoki.judgels.uriel.views.html.contest.contestant.listCreateContestantsView;
import org.iatoki.judgels.uriel.views.html.contest.contestant.listContestantPasswordsView;
import org.iatoki.judgels.uriel.views.html.contest.contestant.updateContestantView;
import org.iatoki.judgels.uriel.views.html.uploadResultView;
import play.data.Form;
import play.db.jpa.Transactional;
import play.filters.csrf.AddCSRFToken;
import play.filters.csrf.RequireCSRFCheck;
import play.i18n.Messages;
import play.mvc.Http;
import play.mvc.Result;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Authenticated(value = {LoggedIn.class, HasRole.class})
@Singleton
@Named
public class ContestContestantController extends AbstractJudgelsController {
private static final long PAGE_SIZE = 1000;
private final Jophiel jophiel;
private final ContestService contestService;
private final ContestContestantService contestContestantService;
private final ContestSupervisorService contestSupervisorService;
private final ContestContestantPasswordService contestContestantPasswordService;
private final UserService userService;
@Inject
public ContestContestantController(Jophiel jophiel, ContestService contestService, ContestContestantService contestContestantService, ContestSupervisorService contestSupervisorService, ContestContestantPasswordService contestContestantPasswordService, UserService userService) {
this.jophiel = jophiel;
this.contestService = contestService;
this.contestContestantService = contestContestantService;
this.contestSupervisorService = contestSupervisorService;
this.contestContestantPasswordService = contestContestantPasswordService;
this.userService = userService;
}
@Transactional(readOnly = true)
@AddCSRFToken
public Result viewContestants(long contestId) throws ContestNotFoundException {
return listCreateContestants(contestId, 0, "id", "asc", "");
}
@Transactional(readOnly = true)
@AddCSRFToken
public Result listCreateContestants(long contestId, long pageIndex, String orderBy, String orderDir, String filterString) throws ContestNotFoundException {
Contest contest = contestService.findContestById(contestId);
if (ContestControllerUtils.getInstance().isSupervisorOrAbove(contest)) {
Page<ContestContestant> contestContestants = contestContestantService.pageContestContestantsByContestJid(contest.getJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
boolean canUpdate = isAllowedToSuperviseContestants(contest);
Form<ContestContestantCreateForm> form = Form.form(ContestContestantCreateForm.class);
Form<ContestContestantUploadForm> form2 = Form.form(ContestContestantUploadForm.class);
return showListCreateContestant(contestContestants, pageIndex, orderBy, orderDir, filterString, canUpdate, form, form2, contest);
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional
@RequireCSRFCheck
public Result postCreateContestant(long contestId, long pageIndex, String orderBy, String orderDir, String filterString) throws ContestNotFoundException {
Contest contest = contestService.findContestById(contestId);
if (isAllowedToSuperviseContestants(contest)) {
Form<ContestContestantCreateForm> form = Form.form(ContestContestantCreateForm.class).bindFromRequest();
if (form.hasErrors() || form.hasGlobalErrors()) {
Form<ContestContestantUploadForm> form2 = Form.form(ContestContestantUploadForm.class);
Page<ContestContestant> contestContestants = contestContestantService.pageContestContestantsByContestJid(contest.getJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
boolean canUpdate = isAllowedToSuperviseContestants(contest);
return showListCreateContestant(contestContestants, pageIndex, orderBy, orderDir, filterString, canUpdate, form, form2, contest);
} else {
ContestContestantCreateForm contestContestantCreateForm = form.get();
try {
String userJid = jophiel.verifyUsername(contestContestantCreateForm.username);
if (userJid != null) {
if (!contestContestantService.isContestContestantInContestByUserJid(contest.getJid(), userJid)) {
userService.upsertUserFromJophielUserJid(userJid);
contestContestantService.createContestContestant(contest.getId(), userJid, ContestContestantStatus.valueOf(contestContestantCreateForm.status));
ControllerUtils.getInstance().addActivityLog("Add contestant " + contestContestantCreateForm.username + " in contest " + contest.getName() + ".");
return redirect(routes.ContestContestantController.viewContestants(contest.getId()));
} else {
Form<ContestContestantUploadForm> form2 = Form.form(ContestContestantUploadForm.class);
form.reject("error.contestant.create.userIsAlreadyContestant");
Page<ContestContestant> contestContestants = contestContestantService.pageContestContestantsByContestJid(contest.getJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
boolean canUpdate = isAllowedToSuperviseContestants(contest);
return showListCreateContestant(contestContestants, pageIndex, orderBy, orderDir, filterString, canUpdate, form, form2, contest);
}
} else {
Form<ContestContestantUploadForm> form2 = Form.form(ContestContestantUploadForm.class);
form.reject("error.contestant.create.userNotExist");
Page<ContestContestant> contestContestants = contestContestantService.pageContestContestantsByContestJid(contest.getJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
boolean canUpdate = isAllowedToSuperviseContestants(contest);
return showListCreateContestant(contestContestants, pageIndex, orderBy, orderDir, filterString, canUpdate, form, form2, contest);
}
} catch (IOException e) {
Form<ContestContestantUploadForm> form2 = Form.form(ContestContestantUploadForm.class);
form.reject("error.contestant.create.userNotExist");
Page<ContestContestant> contestContestants = contestContestantService.pageContestContestantsByContestJid(contest.getJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
boolean canUpdate = isAllowedToSuperviseContestants(contest);
return showListCreateContestant(contestContestants, pageIndex, orderBy, orderDir, filterString, canUpdate, form, form2, contest);
}
}
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional(readOnly = true)
@AddCSRFToken
public Result updateContestant(long contestId, long contestContestantId) throws ContestNotFoundException, ContestContestantNotFoundException {
Contest contest = contestService.findContestById(contestId);
ContestContestant contestContestant = contestContestantService.findContestContestantByContestContestantId(contestContestantId);
if (isAllowedToSuperviseContestants(contest) && contestContestant.getContestJid().equals(contest.getJid())) {
ContestContestantUpdateForm contestContestantUpsertForm = new ContestContestantUpdateForm(contestContestant);
Form<ContestContestantUpdateForm> form = Form.form(ContestContestantUpdateForm.class).fill(contestContestantUpsertForm);
ControllerUtils.getInstance().addActivityLog("Try to update contestant " + contestContestant.getUserJid() + " in contest " + contest.getName() + " <a href=\"" + "http://" + Http.Context.current().request().host() + Http.Context.current().request().uri() + "\">link</a>.");
return showUpdateContestant(form, contest, contestContestant);
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional
@RequireCSRFCheck
public Result postUpdateContestant(long contestId, long contestContestantId) throws ContestNotFoundException, ContestContestantNotFoundException {
Contest contest = contestService.findContestById(contestId);
ContestContestant contestContestant = contestContestantService.findContestContestantByContestContestantId(contestContestantId);
if (isAllowedToSuperviseContestants(contest) && contestContestant.getContestJid().equals(contest.getJid())) {
Form<ContestContestantUpdateForm> form = Form.form(ContestContestantUpdateForm.class).bindFromRequest();
if (form.hasErrors() || form.hasGlobalErrors()) {
return showUpdateContestant(form, contest, contestContestant);
} else {
ContestContestantUpdateForm contestContestantUpdateForm = form.get();
contestContestantService.updateContestContestant(contestContestant.getId(), ContestContestantStatus.valueOf(contestContestantUpdateForm.status));
ControllerUtils.getInstance().addActivityLog("Update contestant " + contestContestant.getUserJid() + " in contest " + contest.getName() + ".");
return redirect(routes.ContestContestantController.viewContestants(contest.getId()));
}
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional
@RequireCSRFCheck
public Result postUploadContestant(long contestId) throws ContestNotFoundException {
Contest contest = contestService.findContestById(contestId);
if (isAllowedToSuperviseContestants(contest)) {
ImmutableList.Builder<UploadResult> failedUploadsBuilder = ImmutableList.builder();
Http.MultipartFormData body = request().body().asMultipartFormData();
Http.MultipartFormData.FilePart file;
file = body.getFile("usernames");
if (file != null) {
File userFile = file.getFile();
try {
String[] usernames = FileUtils.readFileToString(userFile).split("\n");
for (String username : usernames) {
try {
String userJid = jophiel.verifyUsername(username);
if (userJid != null) {
if (!contestContestantService.isContestContestantInContestByUserJid(contest.getJid(), userJid)) {
userService.upsertUserFromJophielUserJid(userJid);
contestContestantService.createContestContestant(contest.getId(), userJid, ContestContestantStatus.APPROVED);
} else {
failedUploadsBuilder.add(new UploadResult(username, Messages.get("error.contestant.isAlreadyContestant")));
}
} else {
failedUploadsBuilder.add(new UploadResult(username, Messages.get("error.contestant.userNotExist")));
}
} catch (IOException e) {
failedUploadsBuilder.add(new UploadResult(username, Messages.get("error.contestant.userNotExist")));
}
}
ControllerUtils.getInstance().addActivityLog("Upload contestants in contest " + contest.getName() + ".");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
List<UploadResult> failedUploads = failedUploadsBuilder.build();
return showUploadContestantResult(failedUploads, contest);
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional(readOnly = true)
public Result viewContestantPasswords(long contestId) throws ContestNotFoundException {
return listContestantPasswords(contestId, 0, "id", "asc", "");
}
@Transactional(readOnly = true)
public Result listContestantPasswords(long contestId, long pageIndex, String orderBy, String orderDir, String filterString) throws ContestNotFoundException {
Contest contest = contestService.findContestById(contestId);
if (contest.requiresPassword() && isAllowedToSuperviseContestants(contest)) {
Page<ContestContestant> contestContestants = contestContestantService.pageContestContestantsByContestJid(contest.getJid(), pageIndex, PAGE_SIZE, orderBy, orderDir, filterString);
Map<String, String> passwordsMap;
if (contest.requiresPassword()) {
passwordsMap = contestContestantPasswordService.getContestantPasswordsMap(contest.getJid(), Lists.transform(contestContestants.getData(), c -> c.getUserJid()));
} else {
passwordsMap = ImmutableMap.of();
}
return showListContestantPasswords(contestContestants, pageIndex, orderBy, orderDir, filterString, passwordsMap, contest);
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional
public Result generateContestantPasswords(long contestId) throws ContestNotFoundException {
Contest contest = contestService.findContestById(contestId);
if (contest.requiresPassword() && isAllowedToSuperviseContestants(contest)) {
contestContestantPasswordService.generateContestantPasswordForAllContestants(contest.getJid());
return redirect(routes.ContestContestantController.viewContestantPasswords(contest.getId()));
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
@Transactional
public Result generateContestantPassword(long contestId, long contestContestantId) throws ContestNotFoundException, ContestContestantNotFoundException {
Contest contest = contestService.findContestById(contestId);
ContestContestant contestant = contestContestantService.findContestContestantByContestContestantId(contestContestantId);
if (contest.requiresPassword() && isAllowedToSuperviseContestants(contest)) {
contestContestantPasswordService.generateContestantPassword(contest.getJid(), contestant.getUserJid());
return redirect(routes.ContestContestantController.viewContestantPasswords(contest.getId()));
} else {
return ContestControllerUtils.getInstance().tryEnteringContest(contest);
}
}
private Result showListCreateContestant(Page<ContestContestant> contestContestants, long pageIndex, String orderBy, String orderDir, String filterString, boolean canUpdate, Form<ContestContestantCreateForm> form, Form<ContestContestantUploadForm> form2, Contest contest){
LazyHtml content = new LazyHtml(listCreateContestantsView.render(contest.getId(), contestContestants, pageIndex, orderBy, orderDir, filterString, canUpdate, form, form2, jophiel.getAutoCompleteEndPoint()));
content.appendLayout(c -> heading3Layout.render(Messages.get("contestant.list"), c));
appendSubtabsLayout(content, contest);
ContestControllerUtils.getInstance().appendTabsLayout(content, contest);
ControllerUtils.getInstance().appendSidebarLayout(content);
appendBreadcrumbsLayout(content, contest,
new InternalLink(Messages.get("contestant.list"), routes.ContestContestantController.viewContestants(contest.getId()))
);
ControllerUtils.getInstance().appendTemplateLayout(content, "Contest - Contestants");
ControllerUtils.getInstance().addActivityLog("Open list of contestants in contest " + contest.getName() + " <a href=\"" + "http://" + Http.Context.current().request().host() + Http.Context.current().request().uri() + "\">link</a>.");
return ControllerUtils.getInstance().lazyOk(content);
}
private Result showUpdateContestant(Form<ContestContestantUpdateForm> form, Contest contest, ContestContestant contestContestant){
LazyHtml content = new LazyHtml(updateContestantView.render(contest.getId(), contestContestant.getId(), form));
content.appendLayout(c -> heading3Layout.render(Messages.get("contestant.update"), c));
appendSubtabsLayout(content, contest);
ContestControllerUtils.getInstance().appendTabsLayout(content, contest);
ControllerUtils.getInstance().appendSidebarLayout(content);
appendBreadcrumbsLayout(content, contest,
new InternalLink(Messages.get("status.supervisor"), routes.ContestContestantController.viewContestants(contest.getId())),
new InternalLink(Messages.get("contestant.update"), routes.ContestContestantController.updateContestant(contest.getId(), contestContestant.getId()))
);
ControllerUtils.getInstance().appendTemplateLayout(content, "Contest - Contestant - Update");
return ControllerUtils.getInstance().lazyOk(content);
}
private Result showListContestantPasswords(Page<ContestContestant> contestContestants, long pageIndex, String orderBy, String orderDir, String filterString, Map<String, String> passwordsMap, Contest contest){
LazyHtml content = new LazyHtml(listContestantPasswordsView.render(contest.getId(), contestContestants, pageIndex, orderBy, orderDir, filterString, passwordsMap));
content.appendLayout(c -> heading3Layout.render(Messages.get("contestant.passwords"), c));
appendSubtabsLayout(content, contest);
ContestControllerUtils.getInstance().appendTabsLayout(content, contest);
ControllerUtils.getInstance().appendSidebarLayout(content);
appendBreadcrumbsLayout(content, contest,
new InternalLink(Messages.get("contestant.passwords"), routes.ContestContestantController.viewContestantPasswords(contest.getId()))
);
ControllerUtils.getInstance().appendTemplateLayout(content, "Contest - Contestants");
ControllerUtils.getInstance().addActivityLog("Open list of contestants in contest " + contest.getName() + " <a href=\"" + "http://" + Http.Context.current().request().host() + Http.Context.current().request().uri() + "\">link</a>.");
return ControllerUtils.getInstance().lazyOk(content);
}
private Result showUploadContestantResult(List<UploadResult> failedUploads, Contest contest) {
LazyHtml content;
if (failedUploads.size() > 0) {
content = new LazyHtml(uploadResultView.render(failedUploads));
} else {
content = new LazyHtml(messageView.render(Messages.get("contestant.upload.success")));
}
content.appendLayout(c -> heading3Layout.render(Messages.get("contestant.upload.result"), c));
appendSubtabsLayout(content, contest);ContestControllerUtils.getInstance().appendTabsLayout(content, contest);
ControllerUtils.getInstance().appendSidebarLayout(content);
appendBreadcrumbsLayout(content, contest,
new InternalLink(Messages.get("contestant.list"), routes.ContestContestantController.viewContestants(contest.getId()))
);
ControllerUtils.getInstance().appendTemplateLayout(content, "Contest - Contestants - Upload Result");
return ControllerUtils.getInstance().lazyOk(content);
}
private void appendSubtabsLayout(LazyHtml content, Contest contest) {
ImmutableList.Builder<InternalLink> internalLinks = ImmutableList.builder();
internalLinks.add(new InternalLink(Messages.get("contestant.contestants"), routes.ContestContestantController.viewContestants(contest.getId())));
internalLinks.add(new InternalLink(Messages.get("team.teams"), routes.ContestTeamController.viewTeams(contest.getId())));
if (contest.requiresPassword()) {
internalLinks.add(new InternalLink(Messages.get("contestant.passwords"), routes.ContestContestantController.viewContestantPasswords(contest.getId())));
}
content.appendLayout(c -> subtabLayout.render(internalLinks.build(), c));
}
private void appendBreadcrumbsLayout(LazyHtml content, Contest contest, InternalLink... lastLinks) {
ControllerUtils.getInstance().appendBreadcrumbsLayout(content,
ContestControllerUtils.getInstance().getContestBreadcrumbsBuilder(contest)
.add(new InternalLink(Messages.get("contestant.contestants"), routes.ContestController.jumpToContestants(contest.getId())))
.addAll(Arrays.asList(lastLinks))
.build()
);
}
private boolean isAllowedToSuperviseContestants(Contest contest) {
return ControllerUtils.getInstance().isAdmin() || ContestControllerUtils.getInstance().isManager(contest) || (ContestControllerUtils.getInstance().isSupervisor(contest) && contestSupervisorService.findContestSupervisorByContestJidAndUserJid(contest.getJid(), IdentityUtils.getUserJid()).getContestPermission().isAllowed(ContestPermissions.CONTESTANT));
}
}