package nl.ipo.cds.admin.ba.controller.gebruikersbeheer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; import javax.validation.Valid; import nl.ipo.cds.admin.ba.controller.gebruikersbeheer.beans.BronhouderThemas; import nl.ipo.cds.admin.ba.controller.gebruikersbeheer.beans.GebruikerThemas; import nl.ipo.cds.dao.ManagerDao; import nl.ipo.cds.domain.Bronhouder; import nl.ipo.cds.domain.BronhouderThema; import nl.ipo.cds.domain.Gebruiker; import nl.ipo.cds.domain.GebruikerThemaAutorisatie; import nl.ipo.cds.domain.Thema; import nl.ipo.cds.domain.TypeGebruik; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Controller for displaying and managing the authorization relationships between * bronhouders and themes and between users and themes. */ @Controller @RequestMapping ("/ba/gebruikersbeheer/autorisatie") public class AutorisatieController { @Inject private ManagerDao managerDao; /** * Displays authorization between bronhouders and themes. */ @RequestMapping (value = "bronhouders", method = RequestMethod.GET) public String showBronhouderThemaAutorisatie (final Model model) { model.addAttribute ("bronhouderThemas", getBronhouderThemas ()); return "/ba/gebruikersbeheer/bronhouder-autorisatie"; } /** * Displays a form to edit the authorization between a single bronhouder and the available themes. * Redirects back to {@link AutorisatieController#showBronhouderThemaAutorisatie(Model)} when the * bronhouder can't be found. */ @RequestMapping (value = "bronhouders/{bronhouderId}/edit", method = RequestMethod.GET) public String showBronhouderThemaAutorisatieForm (final @PathVariable("bronhouderId") long bronhouderId, final Model model) { final Bronhouder bronhouder = managerDao.getBronhouder (bronhouderId); if (bronhouder == null) { return "redirect:/ba/gebruikersbeheer/autorisatie/bronhouders"; } model.addAttribute ("bronhouder", bronhouder); model.addAttribute ("themas", managerDao.getAllThemas ()); model.addAttribute ("selectedThemas", new HashSet<Thema> (managerDao.getAllThemas (bronhouder))); return "/ba/gebruikersbeheer/bronhouder-autorisatie-edit"; } /** * Processes the authorization form for a bronhouder. Redirects back to {@link AutorisatieController#showBronhouderThemaAutorisatie(Model)} * after completing or when the bronhouder can't be found. */ @RequestMapping (value = "bronhouders/{bronhouderId}/edit", method = RequestMethod.POST) @Transactional public String processBronhouderThemaAutorisatieForm ( final @PathVariable("bronhouderId") long bronhouderId, final Model model, final @Valid IdSet idSet, final BindingResult bindingResult) { final Bronhouder bronhouder = managerDao.getBronhouder (bronhouderId); // Redirect immediately in case of an error: if (bronhouder == null || bindingResult.hasErrors ()) { return "redirect:/ba/gebruikersbeheer/autorisatie/bronhouders"; } final Set<Long> ids = idSet.getIds ().keySet (); final Map<Long, BronhouderThema> bronhouderThemas = new HashMap<Long, BronhouderThema> (); // Create a map of BronhouderThemas for convenient lookups: for (final BronhouderThema bronhouderThema: managerDao.getBronhouderThemas (bronhouder)) { bronhouderThemas.put (bronhouderThema.getThema ().getId (), bronhouderThema); } // Insert new BronhouderThema instances: for (final Long id: ids) { if (bronhouderThemas.containsKey (id)) { // An entry already exists: remove from the map and skip. bronhouderThemas.remove (id); continue; } final Thema thema = managerDao.getThema (id); if (thema == null) { continue; } managerDao.create (new BronhouderThema (thema, bronhouder)); } // Remove bronhouder themas that are no longer relevant: for (final BronhouderThema bronhouderThema: bronhouderThemas.values ()) { managerDao.delete (bronhouderThema); } return "redirect:/ba/gebruikersbeheer/autorisatie/bronhouders"; } /** * Displays the authorization between users and themes. */ @RequestMapping (value = "gebruikers", method = RequestMethod.GET) public String showGebruikerThemaAutorisatie (final Model model) { model.addAttribute ("gebruikerThemas", getGebruikerThemas ()); return "/ba/gebruikersbeheer/gebruiker-autorisatie"; } /** * Displays a form to edit the authorization between a single user and all available themes. * Redirects to {@link AutorisatieController#showGebruikerThemaAutorisatie(Model)} if the user * can't be found. */ @RequestMapping (value = "gebruikers/{username}/edit", method = RequestMethod.GET) public String showGebruikerThemaAutorisatieForm (final @PathVariable("username") String username, final Model model) { final Gebruiker gebruiker = managerDao.getGebruiker (username); if (gebruiker == null) { return "redirect:/ba/gebruikersbeheer/autorisatie/gebruikers"; } model.addAttribute ("gebruiker", gebruiker); model.addAttribute ("bronhouderThemas", managerDao.getBronhouderThemas ()); final Map<BronhouderThema, GebruikerThemaAutorisatie> autorisatie = new HashMap<BronhouderThema, GebruikerThemaAutorisatie> (); for (final GebruikerThemaAutorisatie gta: managerDao.getGebruikerThemaAutorisatie (gebruiker)) { autorisatie.put (gta.getBronhouderThema (), gta); } model.addAttribute ("autorisatie", autorisatie); return "/ba/gebruikersbeheer/gebruiker-autorisatie-edit"; } /** * Processes the authorization between a single user and all available themes. * Redirects to {@link AutorisatieController#showGebruikerThemaAutorisatie(Model)} upon completion or if the user * can't be found. */ @RequestMapping (value = "gebruikers/{username}/edit", method = RequestMethod.POST) @Transactional public String processGebruikerThemaAutorisatieForm ( final @PathVariable("username") String username, final Model model, final @Valid AutorisatieMap autorisatieMap, final BindingResult bindingResult) { final Gebruiker gebruiker = managerDao.getGebruiker (username); // Redirect back to the list in case of error: if (gebruiker == null || bindingResult.hasErrors ()) { return "redirect:/ba/gebruikersbeheer/autorisatie/gebruikers"; } // Delete all current authorization for the user: final List<GebruikerThemaAutorisatie> currentGtas = new ArrayList<GebruikerThemaAutorisatie> (managerDao.getGebruikerThemaAutorisatie (gebruiker)); for (final GebruikerThemaAutorisatie gta: currentGtas) { managerDao.delete (gta); } // Insert new authorization for the user: for (final Map.Entry<String, String> entry: autorisatieMap.getAutorisatie ().entrySet ()) { if (entry.getValue () == null || entry.getValue ().isEmpty ()) { continue; } // Decode the typeGebruik value: final TypeGebruik typeGebruik; try { typeGebruik = TypeGebruik.valueOf (entry.getValue ()); } catch (IllegalArgumentException e) { continue; } // Decode the ids and locate thema and bronhouder: final String[] parts = entry.getKey ().split ("\\-"); if (parts.length != 2) { continue; } final Bronhouder bronhouder; final Thema thema; try { bronhouder = managerDao.getBronhouder (Long.parseLong (parts[0])); thema = managerDao.getThema (Long.parseLong (parts[1])); } catch (NumberFormatException e) { continue; } if (bronhouder == null || thema == null) { continue; } // Locate the appropriate BronhouderThema instance: final BronhouderThema bronhouderThema = managerDao.getBronhouderThema (bronhouder, thema); if (bronhouderThema == null) { continue; } // Create the GebruikerThemaAutorisatie relation: managerDao.createGebruikerThemaAutorisatie (gebruiker, bronhouderThema, typeGebruik); } return "redirect:/ba/gebruikersbeheer/autorisatie/gebruikers"; } /** * Combines the list of all users with all {@link GebruikerThemaAutorisatie} associations. * * @return A list of {@link GebruikerThemas} instances each containing a user and associated * {@link GebruikerThemaAutorisatie}'s. */ private List<GebruikerThemas> getGebruikerThemas () { final List<Gebruiker> gebruikers = new ArrayList<Gebruiker> (managerDao.getAllGebruikers ()); final List<GebruikerThemaAutorisatie> gtas = new ArrayList<GebruikerThemaAutorisatie> (managerDao.getGebruikerThemaAutorisatie ()); // Sort both lists on gebruikersnaam: Collections.sort (gebruikers, new Comparator<Gebruiker> () { @Override public int compare (final Gebruiker o1, final Gebruiker o2) { return o1.getGebruikersnaam ().compareTo (o2.getGebruikersnaam ()); } }); Collections.sort (gtas, new Comparator<GebruikerThemaAutorisatie> () { @Override public int compare (final GebruikerThemaAutorisatie o1, final GebruikerThemaAutorisatie o2) { return o1.getGebruiker ().getGebruikersnaam ().compareTo (o2.getGebruiker ().getGebruikersnaam ()); } }); final Set<String> usernames = new HashSet<String> (); for (final Gebruiker gebruiker: gebruikers) { usernames.add (gebruiker.getGebruikersnaam ()); } // Merge the two lists: int i = 0; final List<GebruikerThemas> result = new ArrayList<GebruikerThemas> (); for (final Gebruiker gebruiker: gebruikers) { final List<GebruikerThemaAutorisatie> gebruikerGtas = new ArrayList<GebruikerThemaAutorisatie> (); while (i < gtas.size () && !usernames.contains (gtas.get (i).getGebruiker ().getGebruikersnaam ())) { ++ i; } while (i < gtas.size () && gebruiker.getGebruikersnaam ().equals (gtas.get (i).getGebruiker ().getGebruikersnaam ())) { gebruikerGtas.add (gtas.get (i)); ++ i; } result.add (new GebruikerThemas (gebruiker, gebruikerGtas)); } return Collections.unmodifiableList (result); } /** * Combines the list of all bronhouders with all {@link BronhouderThema} assosications. * * @return A list of {@link BronhouderThemas} instances each containing a bronhouder and * associated {@link Thema}'s. */ private List<BronhouderThemas> getBronhouderThemas () { final List<BronhouderThema> bronhouderThemas = managerDao.getBronhouderThemas (); final List<Bronhouder> bronhouders = new ArrayList<Bronhouder> (managerDao.getAllBronhouders ()); final List<BronhouderThemas> result = new ArrayList<BronhouderThemas> (); // Make sure the bronhouder list is ordered by name: Collections.sort (bronhouders, new Comparator<Bronhouder> () { @Override public int compare (Bronhouder o1, Bronhouder o2) { return o1.getNaam ().compareTo (o2.getNaam ()); } }); int i = 0; for (final Bronhouder bronhouder: bronhouders) { final List<Thema> themas = new ArrayList<Thema> (); while (i < bronhouderThemas.size () && bronhouderThemas.get (i).getBronhouder ().getId ().equals (bronhouder.getId ())) { themas.add (bronhouderThemas.get (i).getThema ()); ++ i; } result.add (new BronhouderThemas (bronhouder, themas)); } return Collections.unmodifiableList (result); } private static class IdSet { @Valid private Map<Long, Boolean> ids = new HashMap<Long, Boolean> (); public Map<Long, Boolean> getIds () { return ids; } @SuppressWarnings("unused") public void setIds (final Map<Long, Boolean> ids) { this.ids = ids; } } private static class AutorisatieMap { @Valid private Map<String, String> autorisatie = new HashMap<String, String> (); public Map<String, String> getAutorisatie () { return autorisatie; } @SuppressWarnings("unused") public void setAutorisatie (final Map<String, String> autorisatie) { this.autorisatie = autorisatie; } } }