add: handling of RA Agent Contract
authorINOPIAE <m.maengel@inopiae.de>
Fri, 6 Jul 2018 12:54:01 +0000 (14:54 +0200)
committerINOPIAE <m.maengel@inopiae.de>
Sun, 1 Dec 2019 05:03:33 +0000 (06:03 +0100)
Only covers the basic functionality.

The full text of the contract and the email will be covered in a later
patch.

The data contract.id and contract.token will be used for pdf-output in a
later patch.

The implementation of the restrictions connected to signed contract will
be covered in a later patch.

Change-Id: I5b47d31458779d227a4f9702a9e7563ab210e7e5

16 files changed:
src/club/wpia/gigi/Gigi.java
src/club/wpia/gigi/database/DatabaseConnection.java
src/club/wpia/gigi/database/tableStructure.sql
src/club/wpia/gigi/database/upgrade/from_37.sql [new file with mode: 0644]
src/club/wpia/gigi/dbObjects/Contract.java [new file with mode: 0644]
src/club/wpia/gigi/dbObjects/ContractNotice.templ [new file with mode: 0644]
src/club/wpia/gigi/dbObjects/User.java
src/club/wpia/gigi/pages/account/MyContracts.java [new file with mode: 0644]
src/club/wpia/gigi/pages/account/MyContracts.templ [new file with mode: 0644]
src/club/wpia/gigi/pages/account/MyDetailsContracts.templ [new file with mode: 0644]
src/club/wpia/gigi/pages/account/MyDetailsForm.java
tests/club/wpia/gigi/dbObjects/TestContract.java [new file with mode: 0644]
tests/club/wpia/gigi/dbObjects/TestUser.java
tests/club/wpia/gigi/testUtils/ConfiguredTest.java
tests/club/wpia/gigi/util/TestNotary.java
util-testing/club/wpia/gigi/pages/Manager.java

index e76c517..d33d546 100644 (file)
@@ -57,6 +57,7 @@ import club.wpia.gigi.pages.Verify;
 import club.wpia.gigi.pages.account.ChangePasswordPage;
 import club.wpia.gigi.pages.account.FindAgentAccess;
 import club.wpia.gigi.pages.account.History;
+import club.wpia.gigi.pages.account.MyContracts;
 import club.wpia.gigi.pages.account.MyDetails;
 import club.wpia.gigi.pages.account.UserTrainings;
 import club.wpia.gigi.pages.account.certs.CertificateAdd;
@@ -195,6 +196,7 @@ public final class Gigi extends HttpServlet {
             putPage(UserTrainings.SUPPORT_PATH, new UserTrainings(true), null);
             putPage(Points.SUPPORT_PATH, new Points(true), null);
             putPage(Certificates.SUPPORT_PATH + "/*", new Certificates(true), null);
+            putPage(MyContracts.PATH, new MyContracts(), null);
 
             putPage(PasswordResetPage.PATH, new PasswordResetPage(), null);
             putPage(LogoutPage.PATH, new LogoutPage(), null);
index b5e78ea..55a597e 100644 (file)
@@ -181,7 +181,7 @@ public class DatabaseConnection {
 
     }
 
-    public static final int CURRENT_SCHEMA_VERSION = 37;
+    public static final int CURRENT_SCHEMA_VERSION = 38;
 
     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
 
index e9097fd..ef7547c 100644 (file)
@@ -372,7 +372,7 @@ CREATE TABLE "schemeVersion" (
   "version" smallint NOT NULL,
   PRIMARY KEY ("version")
 );
-INSERT INTO "schemeVersion" (version)  VALUES(37);
+INSERT INTO "schemeVersion" (version)  VALUES(38);
 
 DROP TABLE IF EXISTS `passwordResetTickets`;
 CREATE TABLE `passwordResetTickets` (
@@ -698,3 +698,22 @@ CREATE TABLE "jobLog" (
   PRIMARY KEY ("jobid", "attempt")
 );
 CREATE INDEX ON "jobLog" ("jobid");
+
+DROP TABLE IF EXISTS "user_contracts";
+DROP TYPE IF EXISTS "contractType";
+CREATE TYPE "contractType" AS ENUM ('RA Agent Contract', 'Org RA Agent Contract');
+
+CREATE TABLE "user_contracts" (
+  "id" serial NOT NULL,
+  "token" varchar(32) NOT NULL,
+  "memid" int NOT NULL,
+  "document" "contractType" NOT NULL,
+  "agentname" varchar(255) NOT NULL,
+  "datesigned" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  "daterevoked" timestamp DEFAULT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX ON "user_contracts" ("memid");
+CREATE INDEX ON "user_contracts" ("document");
+CREATE INDEX ON "user_contracts" ("datesigned");
+CREATE INDEX ON "user_contracts" ("daterevoked");
diff --git a/src/club/wpia/gigi/database/upgrade/from_37.sql b/src/club/wpia/gigi/database/upgrade/from_37.sql
new file mode 100644 (file)
index 0000000..1ac2a4e
--- /dev/null
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS "user_contracts";
+DROP TYPE IF EXISTS "contractType";
+CREATE TYPE "contractType" AS ENUM ('RA Agent Contract', 'Org RA Agent Contract');
+
+CREATE TABLE "user_contracts" (
+  "id" serial NOT NULL,
+  "token" varchar(32) NOT NULL,
+  "memid" int NOT NULL,
+  "document" "contractType" NOT NULL,
+  "agentname" varchar(255) NOT NULL,
+  "datesigned" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  "daterevoked" timestamp DEFAULT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX ON "user_contracts" ("memid");
+CREATE INDEX ON "user_contracts" ("document");
+CREATE INDEX ON "user_contracts" ("datesigned");
+CREATE INDEX ON "user_contracts" ("daterevoked");
diff --git a/src/club/wpia/gigi/dbObjects/Contract.java b/src/club/wpia/gigi/dbObjects/Contract.java
new file mode 100644 (file)
index 0000000..6886dc2
--- /dev/null
@@ -0,0 +1,188 @@
+package club.wpia.gigi.dbObjects;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.database.DBEnum;
+import club.wpia.gigi.database.GigiPreparedStatement;
+import club.wpia.gigi.database.GigiResultSet;
+import club.wpia.gigi.localisation.Language;
+import club.wpia.gigi.output.template.MailTemplate;
+import club.wpia.gigi.util.RandomToken;
+
+public class Contract {
+
+    public enum ContractType implements DBEnum {
+        RA_AGENT_CONTRACT("RA Agent Contract"), ORG_RA_AGENT_CONTRACT("Org RA Agent Contract");
+
+        private final String description;
+
+        private ContractType(String description) {
+            this.description = description;
+        }
+
+        public String getDBName() {
+            return description;
+        }
+    }
+
+    private final ContractType contractType;
+
+    private final User user;
+
+    private String agentname = "";
+
+    private String token = "";
+
+    private Date dateSigned = null;
+
+    private Date dateRevoked = null;
+
+    private int contractID;
+
+    private static final MailTemplate contractNotice = new MailTemplate(Contract.class.getResource("ContractNotice.templ"));
+
+    public Contract(User u, ContractType contractType) throws GigiApiException {
+        this.contractType = contractType;
+        this.user = u;
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `memid`=? AND `document`=?::`contractType` and `daterevoked` IS NULL ORDER BY `datesigned` DESC LIMIT 1")) {
+            query.setInt(1, user.getId());
+            query.setEnum(2, contractType);
+            GigiResultSet rs = query.executeQuery();
+            if (rs.next()) {
+                throw new GigiApiException("Contract exists");
+            } else {
+                signContract();
+            }
+        }
+
+    }
+
+    private void signContract() throws GigiApiException {
+        agentname = user.getPreferredName().toString();
+        token = RandomToken.generateToken(32);
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `user_contracts` SET `memid`=?, `token`=?, `document`=?::`contractType`,`agentname`=?")) {
+            ps.setInt(1, user.getId());
+            ps.setString(2, token);
+            ps.setEnum(3, this.contractType);
+            ps.setString(4, agentname);
+            ps.execute();
+            contractID = ps.lastInsertId();
+            dateSigned = new Date();
+
+            HashMap<String, Object> vars = new HashMap<>();
+            Language l = Language.getInstance(user.getPreferredLocale());
+            vars.put("user", agentname);
+            vars.put("actionsubject", "Signing");
+            vars.put("actionbody", "signed");
+
+            try {
+                contractNotice.sendMail(l, vars, user.getEmail());
+            } catch (IOException e) {
+                throw new GigiApiException("Sending the notification mail failed.");
+            }
+        }
+    }
+
+    public void revokeContract() throws GigiApiException {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `user_contracts` SET `daterevoked`=NOW() WHERE `id`=?")) {
+            ps.setInt(1, contractID);
+            ps.execute();
+        }
+        dateRevoked = new Date();
+        HashMap<String, Object> vars = new HashMap<>();
+        Language l = Language.getInstance(user.getPreferredLocale());
+        vars.put("user", user.getPreferredName());
+        vars.put("actionsubject", "Revoking");
+        vars.put("actionbody", "revoked");
+
+        try {
+            contractNotice.sendMail(l, vars, user.getEmail());
+        } catch (IOException e) {
+            throw new GigiApiException("Sending the notification mail failed.");
+        }
+    }
+
+    private Contract(GigiResultSet rs) {
+        contractID = rs.getInt("id");
+        user = User.getById(rs.getInt("memid"));
+        token = rs.getString("token");
+        contractType = ContractType.valueOf(rs.getString("document").toUpperCase().replace(" ", "_"));
+        dateSigned = rs.getDate("datesigned");
+        dateRevoked = rs.getDate("daterevoked");
+        agentname = rs.getString("agentname");
+    }
+
+    public static Contract getById(int id) {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `id` = ?")) {
+            ps.setInt(1, id);
+            GigiResultSet rs = ps.executeQuery();
+            if ( !rs.next()) {
+                return null;
+            }
+
+            Contract c = new Contract(rs);
+
+            return c;
+        }
+    }
+
+    public int getID() {
+        return contractID;
+    }
+
+    public Date getDateSigned() {
+        return dateSigned;
+    }
+
+    public Date getDateRevoked() {
+        return dateRevoked;
+    }
+
+    public String getRAAgentName() {
+        return agentname;
+    }
+
+    public ContractType getContractType() {
+        return contractType;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public static boolean hasSignedContract(User u, Contract.ContractType ct) {
+        return getContractByUser(u, ct) != null;
+    }
+
+    public static Contract getRAAgentContractByUser(User u) {
+        return getContractByUser(u, Contract.ContractType.RA_AGENT_CONTRACT);
+    }
+
+    public static Contract getContractByUser(User u, ContractType ct) {
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `memid`=? AND `document`=?::`contractType` and `daterevoked` IS NULL ORDER BY `datesigned` DESC LIMIT 1")) {
+            query.setInt(1, u.getId());
+            query.setEnum(2, ct);
+            GigiResultSet rs = query.executeQuery();
+            if ( !rs.next()) {
+                return null;
+            }
+            Contract c = new Contract(rs);
+            return c;
+        }
+    }
+
+    public static Contract getRAAgentContractByToken(String token) throws GigiApiException {
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `token`=? LIMIT 1")) {
+            query.setString(1, token);
+            GigiResultSet rs = query.executeQuery();
+            if ( !rs.next()) {
+                return null;
+            }
+            Contract c = new Contract(rs);
+            return c;
+        }
+    }
+}
diff --git a/src/club/wpia/gigi/dbObjects/ContractNotice.templ b/src/club/wpia/gigi/dbObjects/ContractNotice.templ
new file mode 100644 (file)
index 0000000..e0e499d
--- /dev/null
@@ -0,0 +1,6 @@
+Subject: <?=_${actionsubject} of RA Agent Contract?>
+
+<?=_Hello ${user}, ?>
+
+<?=_you just ${actionbody} the RA Agent Contract.?>
+
index 4612d03..714bfc3 100644 (file)
@@ -242,6 +242,10 @@ public class User extends CertificateOwner {
             return false;
         }
 
+        if ( !Contract.hasSignedContract(this, Contract.ContractType.RA_AGENT_CONTRACT)) {
+            return false;
+        }
+
         return hasPassedCATS();
 
     }
diff --git a/src/club/wpia/gigi/pages/account/MyContracts.java b/src/club/wpia/gigi/pages/account/MyContracts.java
new file mode 100644 (file)
index 0000000..bf0574b
--- /dev/null
@@ -0,0 +1,42 @@
+package club.wpia.gigi.pages.account;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.User;
+import club.wpia.gigi.localisation.Language;
+import club.wpia.gigi.pages.LoginPage;
+import club.wpia.gigi.pages.Page;
+
+public class MyContracts extends Page {
+
+    public static final String PATH = "/account/contracts";
+
+    public MyContracts() {
+        super("My Contracts");
+    }
+
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        PrintWriter out = resp.getWriter();
+        Map<String, Object> vars = getDefaultVars(req);
+        Language l = LoginPage.getLanguage(req);
+        User u = getUser(req);
+        vars.put("raname", u.getPreferredName());
+        vars.put("csdate", l.getTranslation("not yet"));
+
+        Contract c = Contract.getRAAgentContractByUser(u);
+        if (c != null) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            vars.put("csdate", sdf.format(c.getDateSigned()));
+        }
+
+        getDefaultTemplate().output(out, getLanguage(req), vars);
+    }
+}
diff --git a/src/club/wpia/gigi/pages/account/MyContracts.templ b/src/club/wpia/gigi/pages/account/MyContracts.templ
new file mode 100644 (file)
index 0000000..ed1bfe9
--- /dev/null
@@ -0,0 +1,18 @@
+<div class="panel panel-default">
+  <div class="panel-heading"><?=_RA Agents Contract?></div>
+  <div class="panel-body">
+
+       <p>This contract concludes an agreement between</p>
+
+       <p>Name: <?=$raname?> - RA Agent hereafter -</p>
+
+       <p>and</p>
+
+       <p>SomeCA - CA hereafter -</p>
+       <p>SomeAddress</p>
+
+       <p>regarding the conduction of registration authority tasks.</p>
+
+       <p>signed <?=$csdate?></p>
+  </div>
+</div>
diff --git a/src/club/wpia/gigi/pages/account/MyDetailsContracts.templ b/src/club/wpia/gigi/pages/account/MyDetailsContracts.templ
new file mode 100644 (file)
index 0000000..81e0b13
--- /dev/null
@@ -0,0 +1,8 @@
+<div class="panel panel-default">
+  <div class="panel-heading"><?=_RA Agents Contract?></div>
+  <div class="panel-body">
+   <button class="btn btn-info" name="action" value="viewContract"><?=_View RA Agent Contract?></button>
+   <button class="btn btn-primary" name="action" value="signContract" <?=$contractsign?> ><?=_Sign RA Agent Contract?></button>
+   <button class="btn btn-danger" name="action" value="revokeContract" <?=$contractrevoke?> ><?=_Revoke RA Agent Contract?></button>
+  </div>
+</div>
index 13d0388..bf7cbcf 100644 (file)
@@ -7,6 +7,7 @@ import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Contract;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.dbObjects.Name;
 import club.wpia.gigi.dbObjects.User;
@@ -30,6 +31,8 @@ public class MyDetailsForm extends Form {
 
     private static final Template roles = new Template(MyDetailsForm.class.getResource("MyDetailsRoles.templ"));
 
+    private static final Template contracts = new Template(MyDetailsForm.class.getResource("MyDetailsContracts.templ"));
+
     private User target;
 
     private DateSelector ds;
@@ -110,6 +113,17 @@ public class MyDetailsForm extends Form {
                     target.revokeGroup(target, toMod);
                 }
                 return new RedirectResult(MyDetails.PATH);
+            } else if ("viewContract".equals(action)) {
+                return new RedirectResult(MyContracts.PATH);
+            } else if ("signContract".equals(action)) {
+                new Contract(target, Contract.ContractType.RA_AGENT_CONTRACT);
+                return new RedirectResult(MyDetails.PATH);
+            } else if ("revokeContract".equals(action)) {
+                Contract c = Contract.getRAAgentContractByUser(target);
+                if (c != null) {
+                    c.revokeContract();
+                }
+                return new RedirectResult(MyDetails.PATH);
             } else {
                 throw new GigiApiException("Invalid action.");
             }
@@ -161,6 +175,11 @@ public class MyDetailsForm extends Form {
         vars.put("groups", new GroupList(gr, false));
         vars.put("groupSelector", selectedGroup);
         roles.output(out, l, vars);
+
+        boolean hasSignedContract = Contract.hasSignedContract(target, Contract.ContractType.RA_AGENT_CONTRACT);
+        vars.put("contractsign", hasSignedContract ? "disabled" : "");
+        vars.put("contractrevoke", hasSignedContract ? "" : "disabled");
+        contracts.output(out, l, vars);
     }
 
 }
diff --git a/tests/club/wpia/gigi/dbObjects/TestContract.java b/tests/club/wpia/gigi/dbObjects/TestContract.java
new file mode 100644 (file)
index 0000000..98648f0
--- /dev/null
@@ -0,0 +1,91 @@
+package club.wpia.gigi.dbObjects;
+
+import static org.junit.Assert.*;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.testUtils.ClientBusinessTest;
+import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
+import club.wpia.gigi.util.RandomToken;
+
+public class TestContract extends ClientBusinessTest {
+
+    @Test
+    public void testContract() throws GigiApiException {
+
+        assertEquals(Contract.getContractByUser(u, Contract.ContractType.RA_AGENT_CONTRACT), null);
+
+        assertFalse(Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c = Contract.getRAAgentContractByUser(u);
+        assertEquals(c, null);
+
+        c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        TestMail rc = getMailReceiver().receive(u.getEmail());
+
+        assertEquals(u.getEmail(), rc.getTo());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("signed the RA Agent Contract"));
+        assertEquals(u.getPreferredName().toString(), c.getRAAgentName());
+        assertTrue(Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c1 = null;
+        try {
+            c1 = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+            fail("double add contract must fail");
+        } catch (GigiApiException e) {
+            assertEquals("Contract exists", e.getMessage());
+        }
+
+        c1 = Contract.getContractByUser(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        assertEquals(c.getID(), c1.getID());
+
+        c1 = Contract.getRAAgentContractByUser(u);
+        assertEquals(c.getID(), c1.getID());
+
+        c1 = Contract.getRAAgentContractByToken(c.getToken());
+        assertEquals(c.getID(), c1.getID());
+
+        c1 = Contract.getRAAgentContractByToken(RandomToken.generateToken(16));
+        assertEquals(c1, null);
+
+    }
+
+    @Test
+    public void testRevokeContract() throws GigiApiException {
+        Contract c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+
+        TestMail rc = getMailReceiver().receive(u.getEmail());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("signed the RA Agent Contract"));
+
+        c.revokeContract();
+
+        rc = getMailReceiver().receive(u.getEmail());
+        assertEquals(u.getEmail(), rc.getTo());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("revoked the RA Agent Contract"));
+        assertFalse(Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c1 = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        rc = getMailReceiver().receive(u.getEmail());
+
+        assertNotEquals(c.getID(), c1.getID());
+    }
+
+    @Test
+    public void testContractInt() throws GigiApiException {
+        Contract c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+
+        TestMail rc = getMailReceiver().receive(u.getEmail());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("signed the RA Agent Contract"));
+
+        Contract c1 = Contract.getById(c.getID());
+
+        assertEquals(c.getID(), c1.getID());
+        assertEquals(c.getContractType(), c1.getContractType());
+
+        c1 = Contract.getById(0);
+        assertEquals(null, c1);
+    }
+
+}
index 6ec0abe..e7aa70c 100644 (file)
@@ -107,6 +107,19 @@ public class TestUser extends ClientBusinessTest {
         assertTrue(u.hasValidTTPAgentChallenge());
     }
 
+    @Test
+    public void testHasContract() throws GigiApiException {
+        assertEquals(false, Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        getMailReceiver().receive(u.getEmail());
+        assertEquals(true, Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        c.revokeContract();
+        getMailReceiver().receive(u.getEmail());
+        assertEquals(false, Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+    }
+
     @Test
     public void testWriteUserLog() throws GigiApiException {
         String type = "Log test";
index c0d6d4f..845f695 100644 (file)
@@ -42,6 +42,7 @@ import club.wpia.gigi.database.SQLFileManager.ImportType;
 import club.wpia.gigi.dbObjects.CATS;
 import club.wpia.gigi.dbObjects.CATS.CATSType;
 import club.wpia.gigi.dbObjects.CertificateProfile;
+import club.wpia.gigi.dbObjects.Contract.ContractType;
 import club.wpia.gigi.dbObjects.Domain;
 import club.wpia.gigi.dbObjects.DomainPingType;
 import club.wpia.gigi.dbObjects.User;
@@ -52,6 +53,7 @@ import club.wpia.gigi.util.DomainAssessment;
 import club.wpia.gigi.util.Notary;
 import club.wpia.gigi.util.PEM;
 import club.wpia.gigi.util.PasswordHash;
+import club.wpia.gigi.util.RandomToken;
 import club.wpia.gigi.util.ServerConstants;
 import club.wpia.gigi.util.TimeConditions;
 import sun.security.pkcs10.PKCS10;
@@ -361,6 +363,15 @@ public abstract class ConfiguredTest {
             ps2.setInt(2, User.getById(uid).getPreferredName().getId());
             ps2.execute();
         }
+
+        // insert signed RA Contract
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `user_contracts` SET `memid`=?, `token`=?, `document`=?::`contractType`,`agentname`=?")) {
+            ps.setInt(1, uid);
+            ps.setString(2, RandomToken.generateToken(32));
+            ps.setEnum(3, ContractType.RA_AGENT_CONTRACT);
+            ps.setString(4, User.getById(uid).getPreferredName().toString());
+            ps.execute();
+        }
     }
 
     public MailReceiver getMailReceiver() {
index 4028ebd..6c6780e 100644 (file)
@@ -12,6 +12,7 @@ import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.dbObjects.CATS;
 import club.wpia.gigi.dbObjects.CATS.CATSType;
+import club.wpia.gigi.dbObjects.Contract;
 import club.wpia.gigi.dbObjects.Country;
 import club.wpia.gigi.dbObjects.Country.CountryCodeType;
 import club.wpia.gigi.dbObjects.Group;
@@ -23,6 +24,7 @@ import club.wpia.gigi.dbObjects.User;
 import club.wpia.gigi.dbObjects.Verification.VerificationType;
 import club.wpia.gigi.output.DateSelector;
 import club.wpia.gigi.testUtils.BusinessTest;
+import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
 
 public class TestNotary extends BusinessTest {
 
@@ -167,6 +169,8 @@ public class TestNotary extends BusinessTest {
         assertEquals(100, applicant.getVerificationPoints());
         assertFalse(applicant.canVerify());
         CATS.enterResult(applicant, CATSType.AGENT_CHALLENGE, new Date(), "de", "1");
+        new Contract(applicant, Contract.ContractType.RA_AGENT_CONTRACT);
+        TestMail rc = getMailReceiver().receive(applicant.getEmail());
         assertTrue(applicant.canVerify());
     }
 }
index c9dba62..6cce345 100644 (file)
@@ -38,6 +38,8 @@ import club.wpia.gigi.dbObjects.CATS.CATSType;
 import club.wpia.gigi.dbObjects.Certificate;
 import club.wpia.gigi.dbObjects.Certificate.CertificateStatus;
 import club.wpia.gigi.dbObjects.CertificateOwner;
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.Contract.ContractType;
 import club.wpia.gigi.dbObjects.Country;
 import club.wpia.gigi.dbObjects.Digest;
 import club.wpia.gigi.dbObjects.Domain;
@@ -164,6 +166,7 @@ public class Manager extends Page {
                 ps.setString(6, getRandomCountry().getCode());
                 ps.execute();
             }
+            new Contract(u, ContractType.RA_AGENT_CONTRACT);
             return u;
         }
     }