From 5f0c781007ae0ddce24057654a0ab095bc2a2b5b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Wed, 15 Oct 2014 00:30:04 +0200 Subject: [PATCH] WIP orga-things --- doc/tableStructure.sql | 3 +- src/org/cacert/gigi/Gigi.java | 4 + .../gigi/dbObjects/CertificateOwner.java | 76 ++++++++++++++++ .../cacert/gigi/dbObjects/Organisation.java | 87 ++++++++++++++++--- src/org/cacert/gigi/dbObjects/User.java | 76 ---------------- src/org/cacert/gigi/pages/OneFormPage.java | 39 +++++++++ .../gigi/pages/orga/CreateNewOrgPage.java | 21 ----- .../cacert/gigi/pages/orga/CreateOrgForm.java | 69 +++++++++++++++ .../gigi/pages/orga/CreateOrgForm.templ | 34 ++++++++ .../cacert/gigi/pages/orga/CreateOrgPage.java | 47 ++++++++++ .../cacert/gigi/pages/orga/ViewOrgPage.java | 81 +++++++++++++++++ src/org/cacert/gigi/pages/orga/ViewOrgs.templ | 8 ++ tests/org/cacert/gigi/TestOrga.java | 6 +- 13 files changed, 440 insertions(+), 111 deletions(-) create mode 100644 src/org/cacert/gigi/pages/OneFormPage.java delete mode 100644 src/org/cacert/gigi/pages/orga/CreateNewOrgPage.java create mode 100644 src/org/cacert/gigi/pages/orga/CreateOrgForm.java create mode 100644 src/org/cacert/gigi/pages/orga/CreateOrgForm.templ create mode 100644 src/org/cacert/gigi/pages/orga/CreateOrgPage.java create mode 100644 src/org/cacert/gigi/pages/orga/ViewOrgPage.java create mode 100644 src/org/cacert/gigi/pages/orga/ViewOrgs.templ diff --git a/doc/tableStructure.sql b/doc/tableStructure.sql index 55fdfdfc..82c0e82f 100644 --- a/doc/tableStructure.sql +++ b/doc/tableStructure.sql @@ -294,7 +294,7 @@ DROP TABLE IF EXISTS `user_groups`; CREATE TABLE IF NOT EXISTS `user_groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user` int(11) NOT NULL, - `permission` enum('supporter','arbitrator','blockedassuree','blockedassurer','blockedlogin','ttp-assurer','ttp-applicant', 'codesigning') NOT NULL, + `permission` enum('supporter','arbitrator','blockedassuree','blockedassurer','blockedlogin','ttp-assurer','ttp-applicant', 'codesigning', 'orgassurer') NOT NULL, `granted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `deleted` timestamp NULL DEFAULT NULL, `grantedby` int(11) NOT NULL, @@ -306,6 +306,7 @@ DROP TABLE IF EXISTS `org_admin`; CREATE TABLE IF NOT EXISTS `org_admin` ( `orgid` int(11) NOT NULL, `memid` int(11) NOT NULL, + `master` enum('y', 'n') NOT NULL, `creator` int(11) NOT NULL, `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `deleter` int(11) NULL DEFAULT NULL, diff --git a/src/org/cacert/gigi/Gigi.java b/src/org/cacert/gigi/Gigi.java index 60e785b0..10f0c1c2 100644 --- a/src/org/cacert/gigi/Gigi.java +++ b/src/org/cacert/gigi/Gigi.java @@ -44,6 +44,8 @@ import org.cacert.gigi.pages.account.mail.MailOverview; import org.cacert.gigi.pages.admin.TTPAdminPage; import org.cacert.gigi.pages.error.PageNotFound; import org.cacert.gigi.pages.main.RegisterPage; +import org.cacert.gigi.pages.orga.CreateOrgPage; +import org.cacert.gigi.pages.orga.ViewOrgPage; import org.cacert.gigi.pages.wot.AssurePage; import org.cacert.gigi.pages.wot.MyPoints; import org.cacert.gigi.pages.wot.RequestTTPPage; @@ -108,6 +110,8 @@ public class Gigi extends HttpServlet { putPage(MyPoints.PATH, new MyPoints("My Points"), "CAcert Web of Trust"); putPage(RequestTTPPage.PATH, new RequestTTPPage(), "CAcert Web of Trust"); putPage(TTPAdminPage.PATH + "/*", new TTPAdminPage(), "Admin"); + putPage(CreateOrgPage.DEFAULT_PATH, new CreateOrgPage(), "Admin"); + putPage(ViewOrgPage.DEFAULT_PATH + "/*", new ViewOrgPage(), "Admin"); putPage("/wot/rules", new StaticPage("CAcert Web of Trust Rules", AssurePage.class.getResourceAsStream("Rules.templ")), "CAcert Web of Trust"); baseTemplate = new Template(Gigi.class.getResource("Gigi.templ")); rootMenu = new Menu("Main"); diff --git a/src/org/cacert/gigi/dbObjects/CertificateOwner.java b/src/org/cacert/gigi/dbObjects/CertificateOwner.java index cba952c8..1decebb4 100644 --- a/src/org/cacert/gigi/dbObjects/CertificateOwner.java +++ b/src/org/cacert/gigi/dbObjects/CertificateOwner.java @@ -53,4 +53,80 @@ public abstract class CertificateOwner implements IdCachable { return id; } + public EmailAddress[] getEmails() { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM emails WHERE memid=? AND deleted is NULL"); + ps.setInt(1, getId()); + GigiResultSet rs = ps.executeQuery(); + rs.last(); + int count = rs.getRow(); + EmailAddress[] data = new EmailAddress[count]; + rs.beforeFirst(); + for (int i = 0; i < data.length; i++) { + if ( !rs.next()) { + throw new Error("Internal sql api violation."); + } + data[i] = EmailAddress.getById(rs.getInt(1)); + } + rs.close(); + return data; + + } + + public Domain[] getDomains() { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM domains WHERE memid=? AND deleted IS NULL"); + ps.setInt(1, getId()); + GigiResultSet rs = ps.executeQuery(); + rs.last(); + int count = rs.getRow(); + Domain[] data = new Domain[count]; + rs.beforeFirst(); + for (int i = 0; i < data.length; i++) { + if ( !rs.next()) { + throw new Error("Internal sql api violation."); + } + data[i] = Domain.getById(rs.getInt(1)); + } + rs.close(); + return data; + + } + + public Certificate[] getCertificates() { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT serial FROM certs WHERE memid=? AND revoked IS NULL"); + ps.setInt(1, getId()); + GigiResultSet rs = ps.executeQuery(); + rs.last(); + int count = rs.getRow(); + Certificate[] data = new Certificate[count]; + rs.beforeFirst(); + for (int i = 0; i < data.length; i++) { + if ( !rs.next()) { + throw new Error("Internal sql api violation."); + } + data[i] = Certificate.getBySerial(rs.getString(1)); + } + rs.close(); + return data; + + } + + public boolean isValidDomain(String domainname) { + for (Domain d : getDomains()) { + String sfx = d.getSuffix(); + if (domainname.equals(sfx) || domainname.endsWith("." + sfx)) { + return true; + } + } + return false; + } + + public boolean isValidEmail(String email) { + for (EmailAddress em : getEmails()) { + if (em.getAddress().equals(email)) { + return true; + } + } + return false; + } + } diff --git a/src/org/cacert/gigi/dbObjects/Organisation.java b/src/org/cacert/gigi/dbObjects/Organisation.java index d85ffb81..fcd9b2a3 100644 --- a/src/org/cacert/gigi/dbObjects/Organisation.java +++ b/src/org/cacert/gigi/dbObjects/Organisation.java @@ -6,16 +6,48 @@ import java.util.List; import org.cacert.gigi.database.DatabaseConnection; import org.cacert.gigi.database.GigiPreparedStatement; import org.cacert.gigi.database.GigiResultSet; +import org.cacert.gigi.dbObjects.Certificate.CertificateStatus; public class Organisation extends CertificateOwner { - private final String name; + public class Affiliation { - private final String state; + private final User target; - private final String province; + private final boolean master; - private final String city; + private final String fixedOU; + + public Affiliation(User target, boolean master, String fixedOU) { + this.target = target; + this.master = master; + this.fixedOU = fixedOU; + } + + public User getTarget() { + return target; + } + + public boolean isMaster() { + return master; + } + + public String getFixedOU() { + return fixedOU; + } + + public Organisation getOrganisation() { + return Organisation.this; + } + } + + private String name; + + private String state; + + private String province; + + private String city; public Organisation(String name, String state, String province, String city, User creator) { this.name = name; @@ -37,6 +69,7 @@ public class Organisation extends CertificateOwner { } protected Organisation(GigiResultSet rs) { + super(rs.getInt("id")); name = rs.getString("name"); state = rs.getString("state"); province = rs.getString("province"); @@ -67,11 +100,12 @@ public class Organisation extends CertificateOwner { return null; } - public void addAdmin(User admin, User actor) { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO org_admin SET orgid=?, memid=?, creator=?"); + public void addAdmin(User admin, User actor, boolean master) { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO org_admin SET orgid=?, memid=?, creator=?, master=?"); ps.setInt(1, getId()); ps.setInt(2, admin.getId()); ps.setInt(3, actor.getId()); + ps.setString(4, master ? "y" : "n"); ps.execute(); } @@ -83,16 +117,49 @@ public class Organisation extends CertificateOwner { ps.execute(); } - public List getAllAdmins() { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT memid FROM org_admin WHERE orgid=? AND deleted is null"); + public List getAllAdmins() { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT memid, master FROM org_admin WHERE orgid=? AND deleted is null"); ps.setInt(1, getId()); GigiResultSet rs = ps.executeQuery(); rs.last(); - ArrayList al = new ArrayList<>(rs.getRow()); + ArrayList al = new ArrayList<>(rs.getRow()); rs.beforeFirst(); while (rs.next()) { - al.add(User.getById(rs.getInt(1))); + al.add(new Affiliation(User.getById(rs.getInt(1)), rs.getString(2).equals("y"), null)); } return al; } + + public static Organisation[] getOrganisations(int offset, int count) { + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM organisations LIMIT ?,?"); + ps.setInt(1, offset); + ps.setInt(2, count); + GigiResultSet res = ps.executeQuery(); + res.last(); + Organisation[] resu = new Organisation[res.getRow()]; + res.beforeFirst(); + int i = 0; + while (res.next()) { + resu[i++] = getById(res.getInt(1)); + } + return resu; + } + + public void update(String o, String c, String st, String l) { + for (Certificate cert : getCertificates()) { + if (cert.getStatus() == CertificateStatus.ISSUED) { + cert.revoke(); + } + } + GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("UPDATE organisations SET name=?, state=?, province=?, city=?"); + ps.setString(1, o); + ps.setString(2, c); + ps.setString(3, st); + ps.setString(4, l); + ps.execute(); + name = o; + state = c; + province = st; + city = l; + } } diff --git a/src/org/cacert/gigi/dbObjects/User.java b/src/org/cacert/gigi/dbObjects/User.java index 63dc812c..398af91a 100644 --- a/src/org/cacert/gigi/dbObjects/User.java +++ b/src/org/cacert/gigi/dbObjects/User.java @@ -247,82 +247,6 @@ public class User extends CertificateOwner { return System.currentTimeMillis() >= c.getTime().getTime(); } - public EmailAddress[] getEmails() { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM emails WHERE memid=? AND deleted is NULL"); - ps.setInt(1, getId()); - GigiResultSet rs = ps.executeQuery(); - rs.last(); - int count = rs.getRow(); - EmailAddress[] data = new EmailAddress[count]; - rs.beforeFirst(); - for (int i = 0; i < data.length; i++) { - if ( !rs.next()) { - throw new Error("Internal sql api violation."); - } - data[i] = EmailAddress.getById(rs.getInt(1)); - } - rs.close(); - return data; - - } - - public Domain[] getDomains() { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM domains WHERE memid=? AND deleted IS NULL"); - ps.setInt(1, getId()); - GigiResultSet rs = ps.executeQuery(); - rs.last(); - int count = rs.getRow(); - Domain[] data = new Domain[count]; - rs.beforeFirst(); - for (int i = 0; i < data.length; i++) { - if ( !rs.next()) { - throw new Error("Internal sql api violation."); - } - data[i] = Domain.getById(rs.getInt(1)); - } - rs.close(); - return data; - - } - - public Certificate[] getCertificates() { - GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT serial FROM certs WHERE memid=? AND revoked IS NULL"); - ps.setInt(1, getId()); - GigiResultSet rs = ps.executeQuery(); - rs.last(); - int count = rs.getRow(); - Certificate[] data = new Certificate[count]; - rs.beforeFirst(); - for (int i = 0; i < data.length; i++) { - if ( !rs.next()) { - throw new Error("Internal sql api violation."); - } - data[i] = Certificate.getBySerial(rs.getString(1)); - } - rs.close(); - return data; - - } - - public boolean isValidDomain(String domainname) { - for (Domain d : getDomains()) { - String sfx = d.getSuffix(); - if (domainname.equals(sfx) || domainname.endsWith("." + sfx)) { - return true; - } - } - return false; - } - - public boolean isValidEmail(String email) { - for (EmailAddress em : getEmails()) { - if (em.getAddress().equals(email)) { - return true; - } - } - return false; - } - public boolean isValidName(String name) { return getName().matches(name); } diff --git a/src/org/cacert/gigi/pages/OneFormPage.java b/src/org/cacert/gigi/pages/OneFormPage.java new file mode 100644 index 00000000..5eb4db8b --- /dev/null +++ b/src/org/cacert/gigi/pages/OneFormPage.java @@ -0,0 +1,39 @@ +package org.cacert.gigi.pages; + +import java.io.IOException; +import java.util.HashMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.output.Form; + +public class OneFormPage extends Page { + + Class c; + + public OneFormPage(String title, Class t) { + super(title); + c = t; + } + + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + Form.getForm(req, c).submit(resp.getWriter(), req); + } catch (GigiApiException e) { + e.format(resp.getWriter(), getLanguage(req)); + } + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + c.getConstructor(HttpServletRequest.class).newInstance(req).output(resp.getWriter(), getLanguage(req), new HashMap()); + } catch (ReflectiveOperationException e) { + new GigiApiException(e.getMessage()).format(resp.getWriter(), getLanguage(req)); + } + } + +} diff --git a/src/org/cacert/gigi/pages/orga/CreateNewOrgPage.java b/src/org/cacert/gigi/pages/orga/CreateNewOrgPage.java deleted file mode 100644 index 12f24525..00000000 --- a/src/org/cacert/gigi/pages/orga/CreateNewOrgPage.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.cacert.gigi.pages.orga; - -import java.io.IOException; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.cacert.gigi.pages.Page; - -public class CreateNewOrgPage extends Page { - - public CreateNewOrgPage() { - super("Create Organisation"); - } - - @Override - public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - - } - -} diff --git a/src/org/cacert/gigi/pages/orga/CreateOrgForm.java b/src/org/cacert/gigi/pages/orga/CreateOrgForm.java new file mode 100644 index 00000000..df5d4fe2 --- /dev/null +++ b/src/org/cacert/gigi/pages/orga/CreateOrgForm.java @@ -0,0 +1,69 @@ +package org.cacert.gigi.pages.orga; + +import java.io.PrintWriter; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Organisation; +import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.Form; +import org.cacert.gigi.output.template.Template; +import org.cacert.gigi.pages.LoginPage; + +public class CreateOrgForm extends Form { + + private final static Template t = new Template(CreateOrgForm.class.getResource("CreateOrgForm.templ")); + + private Organisation result; + + private String o = ""; + + private String c = ""; + + private String st = ""; + + private String l = ""; + + public CreateOrgForm(HttpServletRequest hsr) { + super(hsr); + } + + public CreateOrgForm(HttpServletRequest hsr, Organisation t) { + super(hsr); + result = t; + o = t.getName(); + c = t.getState(); + st = t.getProvince(); + l = t.getCity(); + } + + @Override + public boolean submit(PrintWriter out, HttpServletRequest req) throws GigiApiException { + o = req.getParameter("O"); + c = req.getParameter("C"); + st = req.getParameter("ST"); + l = req.getParameter("L"); + if (result != null) { + result.update(o, c, st, l); + return true; + } + Organisation ne = new Organisation(o, c, st, l, LoginPage.getUser(req)); + result = ne; + return true; + } + + public Organisation getResult() { + return result; + } + + @Override + protected void outputContent(PrintWriter out, Language l, Map vars) { + vars.put("O", o); + vars.put("C", c); + vars.put("ST", st); + vars.put("L", this.l); + t.output(out, l, vars); + } +} diff --git a/src/org/cacert/gigi/pages/orga/CreateOrgForm.templ b/src/org/cacert/gigi/pages/orga/CreateOrgForm.templ new file mode 100644 index 00000000..3d16d0be --- /dev/null +++ b/src/org/cacert/gigi/pages/orga/CreateOrgForm.templ @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
:
:
:
:
: + ",!"",(2 letter %s ISO code %s )?> +
:
diff --git a/src/org/cacert/gigi/pages/orga/CreateOrgPage.java b/src/org/cacert/gigi/pages/orga/CreateOrgPage.java new file mode 100644 index 00000000..60763e68 --- /dev/null +++ b/src/org/cacert/gigi/pages/orga/CreateOrgPage.java @@ -0,0 +1,47 @@ +package org.cacert.gigi.pages.orga; + +import java.io.IOException; +import java.util.HashMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Group; +import org.cacert.gigi.dbObjects.User; +import org.cacert.gigi.output.Form; +import org.cacert.gigi.pages.Page; + +public class CreateOrgPage extends Page { + + public static final Group ORG_ASSURER = Group.getByString("orgassurer"); + + public static final String DEFAULT_PATH = "/orga/new"; + + public CreateOrgPage() { + super("Create Organisation"); + } + + @Override + public boolean isPermitted(User u) { + return u != null && u.isInGroup(ORG_ASSURER); + } + + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + CreateOrgForm form = Form.getForm(req, CreateOrgForm.class); + if (form.submit(resp.getWriter(), req)) { + resp.sendRedirect(ViewOrgPage.DEFAULT_PATH + "/" + form.getResult().getId()); + return; + } + } catch (GigiApiException e) { + e.format(resp.getWriter(), getLanguage(req)); + } + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + new CreateOrgForm(req).output(resp.getWriter(), getLanguage(req), new HashMap()); + } +} diff --git a/src/org/cacert/gigi/pages/orga/ViewOrgPage.java b/src/org/cacert/gigi/pages/orga/ViewOrgPage.java new file mode 100644 index 00000000..06ed58fd --- /dev/null +++ b/src/org/cacert/gigi/pages/orga/ViewOrgPage.java @@ -0,0 +1,81 @@ +package org.cacert.gigi.pages.orga; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.cacert.gigi.GigiApiException; +import org.cacert.gigi.dbObjects.Organisation; +import org.cacert.gigi.dbObjects.User; +import org.cacert.gigi.localisation.Language; +import org.cacert.gigi.output.Form; +import org.cacert.gigi.output.template.IterableDataset; +import org.cacert.gigi.output.template.Template; +import org.cacert.gigi.pages.Page; + +public class ViewOrgPage extends Page { + + private final Template orgas = new Template(ViewOrgPage.class.getResource("ViewOrgs.templ")); + + public static final String DEFAULT_PATH = "/orga"; + + public ViewOrgPage() { + super("View Organisation"); + } + + @Override + public boolean isPermitted(User u) { + return u != null && u.isInGroup(CreateOrgPage.ORG_ASSURER); + } + + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + Form.getForm(req, CreateOrgForm.class).submit(resp.getWriter(), req); + } catch (GigiApiException e) { + e.format(resp.getWriter(), getLanguage(req)); + } + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String idS = req.getPathInfo(); + Language lang = getLanguage(req); + PrintWriter out = resp.getWriter(); + if (idS.length() < DEFAULT_PATH.length() + 2) { + final Organisation[] orgas = Organisation.getOrganisations(0, 30); + HashMap map = new HashMap<>(); + map.put("orgas", new IterableDataset() { + + int count = 0; + + @Override + public boolean next(Language l, Map vars) { + if (count >= orgas.length) + return false; + Organisation org = orgas[count++]; + System.out.println(org.getId()); + vars.put("id", Integer.toString(org.getId())); + vars.put("name", org.getName()); + vars.put("country", org.getState()); + return true; + } + }); + this.orgas.output(out, lang, map); + return; + } + idS = idS.substring(DEFAULT_PATH.length() + 1); + int id = Integer.parseInt(idS); + Organisation o = Organisation.getById(id); + if (o == null) { + resp.sendError(404); + return; + } + new CreateOrgForm(req, o).output(out, lang, new HashMap()); + out.println(lang.getTranslation("WARNING: updating the data will revoke all issued certificates.")); + } +} diff --git a/src/org/cacert/gigi/pages/orga/ViewOrgs.templ b/src/org/cacert/gigi/pages/orga/ViewOrgs.templ new file mode 100644 index 00000000..2b22950d --- /dev/null +++ b/src/org/cacert/gigi/pages/orga/ViewOrgs.templ @@ -0,0 +1,8 @@ + + + + + + + +
diff --git a/tests/org/cacert/gigi/TestOrga.java b/tests/org/cacert/gigi/TestOrga.java index da4ce25c..e93070d6 100644 --- a/tests/org/cacert/gigi/TestOrga.java +++ b/tests/org/cacert/gigi/TestOrga.java @@ -17,11 +17,11 @@ public class TestOrga extends ManagedTest { User u4 = User.getById(createVerifiedUser("fn", "ln", createUniqueName() + "@email.org", TEST_PASSWORD)); Organisation o1 = new Organisation("name", "ST", "prov", "city", u1); assertEquals(0, o1.getAllAdmins().size()); - o1.addAdmin(u2, u1); + o1.addAdmin(u2, u1, false); assertEquals(1, o1.getAllAdmins().size()); - o1.addAdmin(u3, u1); + o1.addAdmin(u3, u1, false); assertEquals(2, o1.getAllAdmins().size()); - o1.addAdmin(u4, u1); + o1.addAdmin(u4, u1, false); assertEquals(3, o1.getAllAdmins().size()); o1.removeAdmin(u3, u1); assertEquals(2, o1.getAllAdmins().size()); -- 2.39.2