= Напреден апликативен развој = Во последната верзија апликацијата имплементирани се следните сценарија (сите од прототипот и дополнителни): ||= ID =||= UseCase =|| || 1 || Прегледува избирачки список || || 2 || Ажурира избирачки список || || 3 || Прегледува изборни единици || || 4 || Ажурира изборни единици || || 5 || Прегледува гласачки места || || 6 || Aжурира гласачки места || || 7 || Креира инстанца од избори || || 8 || Пријавува учество на партија и кандидати || || 9 || **Назначува членови на комисија** || || 10 || Гласа онлајн || || 11 || **Доделува идентификациски код за гласање со физичко присуство** || || 12 || **Гласа со физичко присуство** || || 13 || Прегледува вкупна излезност || || 14 || **Прегледува статистики од излезност по критериуми** || || 15 || Прегледува вкунпи резултати од избори со кандидат || || 16 || **Прегледува вкунпи резултати од избори со кандидатски листи** || || 16 || **Прегледува статистики од резултати од избори по критериуми** || || 17 || **Поднесува приговор** || || 18 || **Одлучува по приговорот** || || 19 || **Пријавува учество на кандидатски листи** || == Назначува членови на комисија Администраторот пристапува на адреса /admin/committee каде му се отвора страница на која се прикажани сите комисии и формулар за внесување податоци за нова комисија. За ова е одговорен следниот контролер: {{{#!java @GetMapping("admin/committee") public String showCommittee(Model m) { m.addAttribute("realizations", electionRealizationService.findAll()); m.addAttribute("committeeMembers", committeeMemberService.findAll()); m.addAttribute("pollingStations", addressService.findAllPollingStations()); m.addAttribute("committees", committeeService.findAll()); m.addAttribute("committeeForm", new Committee()); m.addAttribute("replaceTemplate", "add_comitee"); return "admin"; } }}} По внесување на податоците и клик на копчето „Запиши“ се праќа POST барање до контролерот кој ги обработува. {{{#!java @PostMapping("/admin/committee") public String addCommittee( @RequestParam(required = false) Long id, @RequestParam Long electionRealization, @RequestParam Long pollingStation, @RequestParam List membersId ) { committeeService.update(id, pollingStation, electionRealization, membersId); return "redirect:/admin/committee"; } }}} Контролерот повикува функција од committeeService за додавање и ажурирање на комисии каде се креира нова инстанца од објектот Committee, и за истиот се полнат добиентите податоци од формуларот. Дополнително, се додаваат и членовите на комисијата кои се во many-to-many релација со комисијата. Оттаму се повикува функцијата save од committeeRepository кој наследува од JpaRepository. Таа служи за зачувување на новиот објект во базата. За да се обезбеди интегритет и конзистентност на податоците, методот е анотиран со @Transactional, односно функцијата успешно ќе заврши ако и само ако успешно се запишат и комисијата и членовите. {{{#!java @Transactional @Override public Committee update(Long id, Long pollingStationId, Long electionRealizationId, List membersId) { Committee committee; if (id != null){ committee = findById(id); } else { committee = new Committee(); } committee.setPollingStation(addressService.findPollingStationById(pollingStationId)); committee.setElectionRealization(electionRealizationService. findById(electionRealizationId)); committeeRepository.save(committee); membersId.forEach(memberId -> addMemberToCommittee(committee.getId(), memberId)); return committeeRepository.save(committee); } }}} Истава имплементација, преточена во SQL прашалникот кој се извршува позадински би изгледала вака: {{{#!sql DO $$ DECLARE new_kom_id BIGINT; BEGIN INSERT INTO komisii (im_id, ri_id) VALUES (1, 1) RETURNING kom_id INTO new_kom_id; INSERT INTO se_clenovi_na (g_id, kom_id) VALUES (20, new_kom_id); INSERT INTO se_clenovi_na (g_id, kom_id) VALUES (21, new_kom_id); INSERT INTO se_clenovi_na (g_id, kom_id) VALUES (22, new_kom_id); INSERT INTO se_clenovi_na (g_id, kom_id) VALUES (23, new_kom_id); INSERT INTO se_clenovi_na (g_id, kom_id) VALUES (24, new_kom_id); COMMIT; END $$; }}} == Доделува идентификациски код за гласање со физичко присуство Корисниците со улога членови на комисија, можат да се најават на системот и пристапат на адресата /admin/electionRealizationInterface, при што добиваат преглед на избирачкиот список од реализацијата којашто се одржува на деновите на најава, за гласачкото место во кое се одговорни. Дополнително, на крајот на редот достапна е акцијата „Гласај“ со што можат да генерираат идентификациски код за гласање доколку гласачот сака да го оствари правото на глас со физичко присуство. Контролерот кој ја опслужува оваа акција е следен: {{{#!java @GetMapping("/admin/electionRealizationInterface") public String showElectionRealization(Model m, Principal p, Authentication authentication) { UserProfile userProfile = (UserProfile) authentication.getPrincipal(); m.addAttribute("realization", committeeService.findElectionRealizationByCitizen(userProfile.getCitizen().getId())); m.addAttribute("citizens", committeeService.getCitizens(userProfile.getCitizen().getId())); m.addAttribute("replaceTemplate","election_realization_interface"); return "index"; } }}} За да се избегнат било какви манипулации и приказ на информации кои не треба да се достапни за најавениот корисник, неговиот идентитет се утврдува директно на серверска страна, од најавениот корисник. Дополнително во сервисите се процесираат реализацијата и избирачкиот список кој треба да го гледа корисникот. {{{#!java @Override public List getCitizens(Long committeeId) { CommitteeMember committeeMember = committeeMemberRepository.findById(committeeId).orElseThrow(RuntimeException::new); Committee committee = committeeRepository.findCommitteeByMembersContainsAndElectionRealization_DateIsAfter(committeeMember, LocalDate.now().minusDays(1)); PollingStation pollingStation = committee.getPollingStation(); return citizenRepository.findAllByAddress_PollingStation(pollingStation.getId()).stream().filter(x -> x instanceof Citizen).toList(); } }}} Во committeeService-от се пронаѓа членот на комисија кој го претставува корисничкиот профил, комисијата во која е член, како и избирачкиот список за гласачкото местоо за кое е одговорна. Во програмската имплементација, ова се прави со повик на соодветни методи од Spring Data JPA, а во SQL би изгледало вака: {{{#!sql select * from komisii k join se_clenovi_na ck on k.kom_id = ck.kom_id join realizacii_na_izbori ri on ri.ri_id = k.ri_id where ck.g_id = 1 and ri.ri_id = 1 and ri.ri_datum = CURRENT_DATE limit 1 }}}