#46, #50: Further improvements on list generation

This commit is contained in:
Simon Brooke 2018-06-11 10:10:23 +01:00
parent 88b693acc5
commit 98695e41dc
6 changed files with 165 additions and 95 deletions

View file

@ -1,6 +1,6 @@
-- File queries.sql -- File queries.sql
-- autogenerated by adl.to-hugsql-queries at -- autogenerated by adl.to-hugsql-queries at
-- 2018-06-05T12:33:53.043Z -- 2018-06-11T00:58:48.917Z
-- See [Application Description Language](https://github.com/simon-brooke/adl). -- See [Application Description Language](https://github.com/simon-brooke/adl).
@ -36,8 +36,7 @@ INSERT INTO canvassers (username,
phone, phone,
email, email,
authority_id, authority_id,
authorised, authorised)
roles)
VALUES (:username, VALUES (:username,
:fullname, :fullname,
:elector_id, :elector_id,
@ -45,8 +44,7 @@ VALUES (:username,
:phone, :phone,
:email, :email,
:authority_id, :authority_id,
:authorised, :authorised)
:roles)
returning id returning id
-- :name create-district! :! :n -- :name create-district! :! :n
@ -494,10 +492,11 @@ ORDER BY canvassers.username,
canvassers.id canvassers.id
-- :name list-canvassers-by-role :? :* -- :name list-canvassers-by-role :? :*
-- :doc lists all existing canvasser records related to a given role -- :doc links all existing canvasser records related to a given role
SELECT * SELECT *
FROM canvassers FROM canvassers
WHERE canvassers.roles = :id WHERE canvassers.roles = link_canvassers_roles.canvasser_id
AND link_canvassers_roles.role_id = :id
ORDER BY canvassers.username, ORDER BY canvassers.username,
canvassers.fullname, canvassers.fullname,
canvassers.email, canvassers.email,
@ -699,6 +698,15 @@ ORDER BY roles.name,
--~ (if (:offset params) "OFFSET :offset ") --~ (if (:offset params) "OFFSET :offset ")
--~ (if (:limit params) "LIMIT :limit" "LIMIT 100") --~ (if (:limit params) "LIMIT :limit" "LIMIT 100")
-- :name list-roles-by-canvasser :? :*
-- :doc links all existing role records related to a given canvasser
SELECT *
FROM roles
WHERE roles.members = link_roles_canvassers.role_id
AND link_roles_canvassers.canvasser_id = :id
ORDER BY roles.name,
roles.id
-- :name list-teammemberships :? :* -- :name list-teammemberships :? :*
-- :doc lists all existing teammembership records -- :doc lists all existing teammembership records
SELECT * FROM teammemberships SELECT * FROM teammemberships
@ -743,6 +751,15 @@ ORDER BY teams.name,
--~ (if (:offset params) "OFFSET :offset ") --~ (if (:offset params) "OFFSET :offset ")
--~ (if (:limit params) "LIMIT :limit" "LIMIT 100") --~ (if (:limit params) "LIMIT :limit" "LIMIT 100")
-- :name list-teams-by-canvasser :? :*
-- :doc links all existing team records related to a given canvasser
SELECT *
FROM teams
WHERE teams.members = link_teams_canvassers.team_id
AND link_teams_canvassers.canvasser_id = :id
ORDER BY teams.name,
teams.id
-- :name list-teams-by-district :? :* -- :name list-teams-by-district :? :*
-- :doc lists all existing team records related to a given district -- :doc lists all existing team records related to a given district
SELECT * SELECT *
@ -967,8 +984,7 @@ SET username = :username,
phone = :phone, phone = :phone,
email = :email, email = :email,
authority_id = :authority_id, authority_id = :authority_id,
authorised = :authorised, authorised = :authorised
roles = :roles
WHERE canvassers.id = :id WHERE canvassers.id = :id
-- :name update-district! :! :n -- :name update-district! :! :n

View file

@ -1,8 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" type="text/css" href="css/yyy-common.css" /> <link rel="stylesheet" type="text/css" href="css/yyy-common.css" />
<link rel="stylesheet" type="text/css" href="css/yyy-site.css" /> <link rel="stylesheet" type="text/css" href="css/yyy-site.css" />
<link rel="stylesheet" type="text/css" href="css/spinner.css" /> <link rel="stylesheet" type="text/css" href="css/spinner.css" />
@ -11,6 +11,7 @@
</head> </head>
<body> <body>
{% block whole-page %} {% block whole-page %}
{% block top %}
<header> <header>
<div id="nav"> <div id="nav">
<img id="nav-icon" src="img/threelines.png" alt="Menu"/> <img id="nav-icon" src="img/threelines.png" alt="Menu"/>
@ -31,7 +32,7 @@
{{title}} {{title}}
</h1> </h1>
</header> </header>
{% endblock %}
<div id="main-container" class="container"> <div id="main-container" class="container">
<div id="big-links"> <div id="big-links">
{% block big-links %} {% block big-links %}
@ -45,6 +46,7 @@
<a href="javascript:history.back()" id="back-link">Back</a> <a href="javascript:history.back()" id="back-link">Back</a>
</div> </div>
</div> </div>
{% block foot %}
<footer> <footer>
<div id="credits"> <div id="credits">
<div> <div>
@ -62,6 +64,7 @@
</div> </div>
</footer> </footer>
{% endblock %} {% endblock %}
{% endblock %}
<script type="text/javascript"> <script type="text/javascript">
var context = "{{servlet-context}}"; var context = "{{servlet-context}}";
var csrfToken = "{{csrf-token}}"; var csrfToken = "{{csrf-token}}";

View file

@ -56,7 +56,7 @@
list-addresses-by-district list-addresses-by-district
list-authorities list-authorities
list-canvassers list-canvassers
list-canvassers-by-addresse list-canvassers-by-address
list-canvassers-by-authoritie list-canvassers-by-authoritie
list-canvassers-by-elector list-canvassers-by-elector
list-districts list-districts
@ -110,7 +110,7 @@
(defroutes (defroutes
auto-rest-routes auto-rest-routes
(POST "/json/auto/create-addresse" request (create-address request)) (POST "/json/auto/create-address" request (create-address request))
(POST (POST
"/json/auto/create-authority" "/json/auto/create-authority"
request request
@ -162,7 +162,7 @@
request request
(create-teamorganisership request)) (create-teamorganisership request))
(POST "/json/auto/create-visit" request (create-visit request)) (POST "/json/auto/create-visit" request (create-visit request))
(POST "/json/auto/delete-addresse" request (delete-address request)) (POST "/json/auto/delete-address" request (delete-address request))
(POST (POST
"/json/auto/delete-authority" "/json/auto/delete-authority"
request request
@ -188,7 +188,7 @@
(POST "/json/auto/delete-issue" request (delete-issue request)) (POST "/json/auto/delete-issue" request (delete-issue request))
(POST "/json/auto/delete-option" request (delete-option request)) (POST "/json/auto/delete-option" request (delete-option request))
(POST "/json/auto/delete-visit" request (delete-visit request)) (POST "/json/auto/delete-visit" request (delete-visit request))
(POST "/json/auto/get-addresse" request (get-addresse request)) (POST "/json/auto/get-address" request (get-address request))
(POST "/json/auto/get-authority" request (get-authority request)) (POST "/json/auto/get-authority" request (get-authority request))
(POST "/json/auto/get-canvasser" request (get-canvasser request)) (POST "/json/auto/get-canvasser" request (get-canvasser request))
(POST "/json/auto/get-district" request (get-district request)) (POST "/json/auto/get-district" request (get-district request))
@ -216,9 +216,9 @@
(GET "/json/auto/list-authorities" request (list-authorities request)) (GET "/json/auto/list-authorities" request (list-authorities request))
(GET "/json/auto/list-canvassers" request (list-canvassers request)) (GET "/json/auto/list-canvassers" request (list-canvassers request))
(GET (GET
"/json/auto/list-canvassers-by-addresse" "/json/auto/list-canvassers-by-address"
request request
(list-canvassers-by-addresse request)) (list-canvassers-by-address request))
(GET (GET
"/json/auto/list-canvassers-by-authoritie" "/json/auto/list-canvassers-by-authoritie"
request request
@ -230,9 +230,9 @@
(GET "/json/auto/list-districts" request (list-districts request)) (GET "/json/auto/list-districts" request (list-districts request))
(GET "/json/auto/list-electors" request (list-electors request)) (GET "/json/auto/list-electors" request (list-electors request))
(GET (GET
"/json/auto/list-electors-by-addresse" "/json/auto/list-electors-by-address"
request request
(list-electors-by-addresse request)) (list-electors-by-address request))
(GET (GET
"/json/auto/list-followupactions" "/json/auto/list-followupactions"
request request
@ -355,14 +355,14 @@
(list-teams-by-district request)) (list-teams-by-district request))
(GET "/json/auto/list-visits" request (list-visits request)) (GET "/json/auto/list-visits" request (list-visits request))
(GET (GET
"/json/auto/list-visits-by-addresse" "/json/auto/list-visits-by-address"
request request
(list-visits-by-addresse request)) (list-visits-by-address request))
(GET (GET
"/json/auto/list-visits-by-canvasser" "/json/auto/list-visits-by-canvasser"
request request
(list-visits-by-canvasser request)) (list-visits-by-canvasser request))
(POST "/json/auto/update-addresse" request (update-addresse request)) (POST "/json/auto/update-address" request (update-address request))
(POST (POST
"/json/auto/update-canvasser" "/json/auto/update-canvasser"
request request
@ -603,10 +603,10 @@
(defn (defn
get-addresse get-address
"Auto-generated method to select one record from the addresses table. Expects the following key(s) to be present in `params`: (:id). Returns a map containing the following keys: (:address :district_id :id :latitude :longitude :phone :postcode)." "Auto-generated method to select one record from the addresses table. Expects the following key(s) to be present in `params`: (:id). Returns a map containing the following keys: (:address :district_id :id :latitude :longitude :phone :postcode)."
[{:keys [params]}] [{:keys [params]}]
(do (db/get-addresse params))) (do (db/get-address params)))
(defn (defn
@ -707,9 +707,9 @@
(defn (defn
list-canvassers-by-addresse list-canvassers-by-address
[{:keys [params]}] [{:keys [params]}]
(do (db/list-canvassers-by-addresse params))) (do (db/list-canvassers-by-address params)))
(defn (defn
@ -739,9 +739,9 @@
(defn (defn
list-electors-by-addresse list-electors-by-address
[{:keys [params]}] [{:keys [params]}]
(do (db/list-electors-by-addresse params))) (do (db/list-electors-by-address params)))
(defn (defn
@ -958,9 +958,9 @@
(defn (defn
list-visits-by-addresse list-visits-by-address
[{:keys [params]}] [{:keys [params]}]
(do (db/list-visits-by-addresse params))) (do (db/list-visits-by-address params)))
(defn (defn

View file

@ -57,7 +57,7 @@
[session (:session request) [session (:session request)
username (:user session) username (:user session)
user (if username (db-core/get-canvasser-by-username db-core/*db* {:username username})) user (if username (db-core/get-canvasser-by-username db-core/*db* {:username username}))
roles (if user (db-core/get-roles-by-canvasser db-core/*db* {:canvasser (:id user)}))] roles (if user (db-core/list-roles-by-canvasser db-core/*db* {:id (:id user)}))]
(cond (cond
roles (layout/render "roles.html" roles (layout/render "roles.html"
{:title (str "Welcome " (:fullname user) ", what do you want to do?") {:title (str "Welcome " (:fullname user) ", what do you want to do?")

View file

@ -3,6 +3,7 @@
"http://www.journeyman.cc/adl/stable/adl/schemas/adl-1.4.1.dtd" --> "http://www.journeyman.cc/adl/stable/adl/schemas/adl-1.4.1.dtd" -->
<application name="youyesyet" version="0.1.1" <application name="youyesyet" version="0.1.1"
xmlns="http://bowyer.journeyman.cc/adl/1.4.1/" xmlns="http://bowyer.journeyman.cc/adl/1.4.1/"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:adl="http://bowyer.journeyman.cc/adl/1.4.1/"> xmlns:adl="http://bowyer.journeyman.cc/adl/1.4.1/">
<documentation> <documentation>
A web-app intended to be used by canvassers campaigning for a 'Yes' vote in the second independence referendum. A web-app intended to be used by canvassers campaigning for a 'Yes' vote in the second independence referendum.
@ -12,9 +13,34 @@
There must also be an administrative interface through which privileged users can set the system up and authorise canvassers, and a 'followup' interface through which issue-expert specialist canvassers can address particular electors' queries. There must also be an administrative interface through which privileged users can set the system up and authorise canvassers, and a 'followup' interface through which issue-expert specialist canvassers can address particular electors' queries.
</documentation> </documentation>
<content> <content>
<head> </head> <head>
<html:meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<html:meta name="viewport" content="width=device-width, initial-scale=1"/>
<html:link rel="stylesheet" type="text/css" href="css/yyy-common.css" />
<html:link rel="stylesheet" type="text/css" href="css/yyy-site.css" />
<html:link rel="stylesheet" type="text/css" href="css/spinner.css" />
<html:link href="https://fonts.googleapis.com/css?family=Archivo+Black|Archivo+Narrow" rel="stylesheet"/>
<html:title>{{site-title}}: {{title}}</html:title>
</head>
<top> </top> <top> </top>
<foot> </foot> <foot>
<html:footer>
<html:div id="credits">
<html:div>
<html:img src="img/credits/ric-logo.png" width="24" height="24"/>
A project of the
<html:a href="https://radical.scot/">Radical Independence Campaign</html:a> ||
Version {{version}}
</html:div>
<html:div>
<html:img height="16" width="16" alt="Clojure" src="img/credits/luminus-logo.png"/>Built with <html:a href="http://www.luminusweb.net/">LuminusWeb</html:a> ||
<html:img height="16" width="16" alt="Clojure" src="img/credits/clojure-icon.gif"/> Powered by <html:a href="http://clojure.org">Clojure</html:a> ||
<html:img height="16" width="16" alt="GitHub" src="img/credits/github-logo-transparent.png"/>Find me/fork me on <html:a href="https://github.com/simon-brooke/smeagol">Github</html:a> ||
<html:img height="16" width="16" alt="Free Software Foundation" src="img/credits/gnu.small.png"/>Licensed under the <html:a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License version 2.0</html:a>
</html:div>
</html:div>
</html:footer>
</foot>
</content> </content>
<typedef name="postcode" type="string" <typedef name="postcode" type="string"
pattern="^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$" size="16"> pattern="^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$" size="16">
@ -143,7 +169,7 @@
<prompt prompt="id" locale="en-GB"/> <prompt prompt="id" locale="en-GB"/>
</property> </property>
</key> </key>
<property required="true" type="integer" name="address_id" column="address_id" <property required="true" type="entity" name="address_id" column="address_id"
entity="addresses" farkey="id"> entity="addresses" farkey="id">
<prompt prompt="address_id" locale="en-GB"/> <prompt prompt="address_id" locale="en-GB"/>
</property> </property>
@ -218,7 +244,7 @@
<property type="entity" name="elector_id" column="elector_id" entity="electors" farkey="id"> <property type="entity" name="elector_id" column="elector_id" entity="electors" farkey="id">
<prompt prompt="elector_id" locale="en-GB"/> <prompt prompt="elector_id" locale="en-GB"/>
</property> </property>
<property required="true" type="integer" name="address_id" column="address_id" <property required="true" type="entity" name="address_id" column="address_id"
entity="addresses" farkey="id"> entity="addresses" farkey="id">
<prompt prompt="address_id" locale="en-GB"/> <prompt prompt="address_id" locale="en-GB"/>
</property> </property>
@ -369,7 +395,7 @@
entity="followuprequests" farkey="id"> entity="followuprequests" farkey="id">
<prompt prompt="request_id" locale="en-GB"/> <prompt prompt="request_id" locale="en-GB"/>
</property> </property>
<property required="true" type="integer" name="actor" column="actor" entity="canvassers" <property required="true" type="entity" name="actor" column="actor" entity="canvassers"
farkey="id"> farkey="id">
<prompt prompt="actor" locale="en-GB"/> <prompt prompt="actor" locale="en-GB"/>
</property> </property>
@ -392,7 +418,7 @@
</entity> </entity>
<entity name="issueexpertise" magnitude="5"> <entity name="issueexpertise" magnitude="5">
<documentation>Link table</documentation> <documentation>Link table</documentation>
<property required="true" type="integer" name="canvasser_id" column="canvasser_id" <property required="true" type="entity" name="canvasser_id" column="canvasser_id"
entity="canvassers" farkey="id"> entity="canvassers" farkey="id">
<prompt prompt="canvasser_id" locale="en-GB"/> <prompt prompt="canvasser_id" locale="en-GB"/>
</property> </property>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- DOCTYPE application PUBLIC "-//JOURNEYMAN//DTD ADL 1.4.1//EN" <!-- DOCTYPE application PUBLIC "-//JOURNEYMAN//DTD ADL 1.4.1//EN"
"http://www.journeyman.cc/adl/stable/adl/schemas/adl-1.4.1.dtd" --> "http://www.journeyman.cc/adl/stable/adl/schemas/adl-1.4.1.dtd" -->
<application xmlns="http://bowyer.journeyman.cc/adl/1.4.1/" xmlns:adl="http://bowyer.journeyman.cc/adl/1.4.1/" name="youyesyet" version="0.1.1"> <application xmlns="http://bowyer.journeyman.cc/adl/1.4.1/" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:adl="http://bowyer.journeyman.cc/adl/1.4.1/" name="youyesyet" version="0.1.1">
<!-- <!--
*************************************************************************** ***************************************************************************
* *
@ -22,9 +22,34 @@
There must also be an administrative interface through which privileged users can set the system up and authorise canvassers, and a 'followup' interface through which issue-expert specialist canvassers can address particular electors' queries. There must also be an administrative interface through which privileged users can set the system up and authorise canvassers, and a 'followup' interface through which issue-expert specialist canvassers can address particular electors' queries.
</documentation> </documentation>
<content> <content>
<head> </head> <head>
<html:meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<html:meta name="viewport" content="width=device-width, initial-scale=1"/>
<html:link rel="stylesheet" type="text/css" href="css/yyy-common.css"/>
<html:link rel="stylesheet" type="text/css" href="css/yyy-site.css"/>
<html:link rel="stylesheet" type="text/css" href="css/spinner.css"/>
<html:link href="https://fonts.googleapis.com/css?family=Archivo+Black|Archivo+Narrow" rel="stylesheet"/>
<html:title>{{site-title}}: {{title}}</html:title>
</head>
<top> </top> <top> </top>
<foot> </foot> <foot>
<html:footer>
<html:div id="credits">
<html:div>
<html:img src="img/credits/ric-logo.png" width="24" height="24"/>
A project of the
<html:a href="https://radical.scot/">Radical Independence Campaign</html:a> ||
Version {{version}}
</html:div>
<html:div>
<html:img height="16" width="16" alt="Clojure" src="img/credits/luminus-logo.png"/>Built with <html:a href="http://www.luminusweb.net/">LuminusWeb</html:a> ||
<html:img height="16" width="16" alt="Clojure" src="img/credits/clojure-icon.gif"/> Powered by <html:a href="http://clojure.org">Clojure</html:a> ||
<html:img height="16" width="16" alt="GitHub" src="img/credits/github-logo-transparent.png"/>Find me/fork me on <html:a href="https://github.com/simon-brooke/smeagol">Github</html:a> ||
<html:img height="16" width="16" alt="Free Software Foundation" src="img/credits/gnu.small.png"/>Licensed under the <html:a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License version 2.0</html:a>
</html:div>
</html:div>
</html:footer>
</foot>
</content> </content>
<typedef name="postcode" type="string" pattern="^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$" size="16"> <typedef name="postcode" type="string" pattern="^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$" size="16">
<documentation>See <documentation>See
@ -177,7 +202,7 @@
<prompt prompt="id" locale="en-GB"/> <prompt prompt="id" locale="en-GB"/>
</property> </property>
</key> </key>
<property required="true" type="integer" name="address_id" column="address_id" entity="addresses" farkey="id"> <property required="true" type="entity" name="address_id" column="address_id" entity="addresses" farkey="id">
<prompt prompt="address_id" locale="en-GB"/> <prompt prompt="address_id" locale="en-GB"/>
</property> </property>
<property required="true" type="entity" name="canvasser_id" column="canvasser_id" entity="canvassers" farkey="id"> <property required="true" type="entity" name="canvasser_id" column="canvasser_id" entity="canvassers" farkey="id">
@ -294,7 +319,7 @@
<property type="entity" name="elector_id" column="elector_id" entity="electors" farkey="id"> <property type="entity" name="elector_id" column="elector_id" entity="electors" farkey="id">
<prompt prompt="elector_id" locale="en-GB"/> <prompt prompt="elector_id" locale="en-GB"/>
</property> </property>
<property required="true" type="integer" name="address_id" column="address_id" entity="addresses" farkey="id"> <property required="true" type="entity" name="address_id" column="address_id" entity="addresses" farkey="id">
<prompt prompt="address_id" locale="en-GB"/> <prompt prompt="address_id" locale="en-GB"/>
</property> </property>
<property type="string" name="phone" column="phone" size="16"> <property type="string" name="phone" column="phone" size="16">
@ -484,7 +509,7 @@
<property required="true" type="entity" name="request_id" column="request_id" entity="followuprequests" farkey="id"> <property required="true" type="entity" name="request_id" column="request_id" entity="followuprequests" farkey="id">
<prompt prompt="request_id" locale="en-GB"/> <prompt prompt="request_id" locale="en-GB"/>
</property> </property>
<property required="true" type="integer" name="actor" column="actor" entity="canvassers" farkey="id"> <property required="true" type="entity" name="actor" column="actor" entity="canvassers" farkey="id">
<prompt prompt="actor" locale="en-GB"/> <prompt prompt="actor" locale="en-GB"/>
</property> </property>
<property required="true" default="" type="timestamp" name="date" column="date"> <property required="true" default="" type="timestamp" name="date" column="date">
@ -517,7 +542,7 @@
</documentation> </documentation>
</property> </property>
</key> </key>
<property required="true" type="integer" name="canvasser_id" column="canvasser_id" entity="canvassers" farkey="id"> <property required="true" type="entity" name="canvasser_id" column="canvasser_id" entity="canvassers" farkey="id">
<prompt prompt="canvasser_id" locale="en-GB"/> <prompt prompt="canvasser_id" locale="en-GB"/>
</property> </property>
<property required="true" type="entity" name="issue_id" column="issue_id" entity="issues" farkey="id"> <property required="true" type="entity" name="issue_id" column="issue_id" entity="issues" farkey="id">