comparison src/nabble/modules/poll/Poll.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:7ecd1a4ef557
1 package nabble.modules.poll;
2
3 import java.io.Serializable;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.util.ArrayList;
7 import java.util.Date;
8 import java.util.List;
9 import fschmidt.db.DbNull;
10 import fschmidt.db.DbRecord;
11 import fschmidt.db.LongKey;
12 import nabble.model.ModelException;
13 import nabble.model.Node;
14 import nabble.model.User;
15 import nabble.model.ExtensionFactory;
16 import nabble.model.ModelHome;
17
18
19 final class Poll {
20
21
22 private static final ExtensionFactory<Node,Poll> FACTORY = new ExtensionFactory<Node,Poll>() {
23
24 public String getName() {
25 return PollModule.INSTANCE.getName();
26 }
27
28 public Class<Poll> extensionClass() {
29 return Poll.class;
30 }
31
32 public Poll construct(Node node) {
33 return null;
34 }
35
36 public Poll construct(Node node,ResultSet rs)
37 throws SQLException
38 {
39 int pollOptionCount = rs.getInt("poll_option_count");
40 if( pollOptionCount==0 )
41 return null;
42 return new Poll(node,pollOptionCount);
43 }
44
45 public Serializable getExportData(Node node) {
46 return null; //throw new UnsupportedOperationException();
47 }
48
49 public void saveExportData(Node node,Serializable s) {
50 //throw new UnsupportedOperationException();
51 }
52 };
53
54 static {
55 ModelHome.addNodeExtensionFactory(FACTORY);
56 }
57
58 static void init() {}
59
60 public static Poll of(Node node) {
61 return node.getExtension(FACTORY);
62 }
63
64
65
66
67
68 private final Node node;
69 private int pollOptionCount;
70 private String question;
71 private String[] options;
72 private int maxChoices = 1;
73 private Date endDate = null;
74 private boolean allowVoteChange = true;
75 private boolean showResultsBeforeVote = true;
76 private boolean showResultsBeforeEnd = true;
77
78 Poll(Node node,int pollOptionCount) {
79 this.node = node;
80 this.pollOptionCount = pollOptionCount;
81 this.question = node.getProperty("poll_question");
82 this.options = new String[pollOptionCount];
83 for (int i=0; i<options.length; i++)
84 this.options[i] = node.getProperty("poll_option_"+i);
85 String maxChoicesS = node.getProperty("poll_max_choices");
86 maxChoices = maxChoicesS!=null ? Integer.parseInt(maxChoicesS) : 1;
87 String endtime = node.getProperty("poll_end_date");
88 endDate = endtime == null ? null : new Date(Long.parseLong(endtime));
89 allowVoteChange = !"false".equals(node.getProperty("poll_allow_vote_change"));
90 showResultsBeforeVote = !"false".equals(node.getProperty("poll_show_results_before_vote"));
91 showResultsBeforeEnd = !"false".equals(node.getProperty("poll_show_results_before_end"));
92 }
93
94 void set(String question, String[] options) throws PollFormatException {
95 if( !node.getSite().getDb().isInTransaction() )
96 throw new RuntimeException("not in transaction");
97 if (question.trim().length()==0 || options.length < 2)
98 throw new PollFormatException();
99 this.pollOptionCount = options.length;
100 DbRecord<LongKey,?> record = node.getDbRecord();
101 record.fields().put("poll_option_count", pollOptionCount);
102 record.update();
103 this.question = question.trim();
104 node.setProperty("poll_question", question.trim());
105 this.options = new String[options.length];
106 for (int i=0; i<options.length; i++) {
107 String option = options[i].trim();
108 if (option.length()==0)
109 throw new PollFormatException();
110 this.options[i] = option;
111 node.setProperty("poll_option_"+i, option);
112 }
113 clearVotes();
114 }
115
116 Node getNode() {
117 return node;
118 }
119
120 String getQuestion() {
121 return question;
122 }
123
124 String[] getOptions() {
125 return options;
126 }
127
128 int[] getVoteCounts() {
129 int[] votes = new int[options.length];
130 for (int i=0; i<options.length; i++) {
131 votes[i] = node.getSite().countTags("node_id="+node.getId()+"and label='"+VOTE_LABEL_PREFIX+i+"'");
132 }
133 return votes;
134 }
135
136 private static final String VOTE_LABEL_PREFIX="poll_vote:";
137
138 int[] getVotes(User user) {
139 List<Integer> v = new ArrayList<Integer>();
140 for (int i=0; i<options.length; i++) {
141 boolean vote = node.getSite().hasTags(node, user, "label='"+VOTE_LABEL_PREFIX+i+"'");
142 if (vote) v.add(i); // duplicates aren't possible because the index is unique
143 }
144 int[] votes = new int[v.size()];
145 for (int i=0; i<votes.length; i++)
146 votes[i] = v.get(i);
147 return votes;
148 /*
149 List<String> labels = node.getSite().findTagLabels(
150 "node_id="+node.getId()+" and user_id="+user.getId()+" and label like '"+VOTE_LABEL_PREFIX+"%'"
151 );
152 int[] votes = new int[labels.size()];
153 for (int i=0; i<votes.length; i++) {
154 votes[i] = Integer.parseInt(labels.get(i).substring(VOTE_LABEL_PREFIX.length()));
155 }
156 return votes;
157 */
158 }
159
160 void vote(User user, int[] votes) throws PollVoteException {
161 if (votes.length > maxChoices)
162 throw new PollVoteException();
163 if (!allowVoteChange && getVotes(user).length>0)
164 throw new PollVoteException();
165 if (endDate!=null && endDate.before(new Date()))
166 throw new PollVoteException();
167 node.getSite().deleteTags(node, user, "label like '"+VOTE_LABEL_PREFIX+"%'");
168 for (int vote : votes) {
169 node.getSite().addTag(node, user, VOTE_LABEL_PREFIX+vote);
170 }
171 }
172
173 private void clearVotes() {
174 node.getSite().deleteTags(
175 "node_id="+node.getId()+" and label like '"+VOTE_LABEL_PREFIX+"%'"
176 );
177 }
178
179 void delete() {
180 if( !node.getSite().getDb().isInTransaction() )
181 throw new RuntimeException("not in transaction");
182 node.setProperty("poll_question", null);
183 for (int i=0; i<pollOptionCount; i++) {
184 node.setProperty("poll_option_"+i, null);
185 }
186 node.setProperty("poll_max_choices", null);
187 node.setProperty("poll_end_date", null);
188 node.setProperty("poll_allow_vote_change", null);
189 node.setProperty("poll_show_results_before_vote", null);
190 node.setProperty("poll_show_results_before_end", null);
191 clearVotes();
192 DbRecord<LongKey,?> record = node.getDbRecord();
193 record.fields().put("poll_option_count", DbNull.INTEGER);
194 record.update();
195 }
196
197
198 int maxChoices() {
199 return maxChoices;
200 }
201
202 Date endDate() {
203 return endDate;
204 }
205
206 boolean allowVoteChange() {
207 return allowVoteChange;
208 }
209
210 boolean showResultsBeforeVote() {
211 return showResultsBeforeVote;
212 }
213
214 boolean showResultsBeforeEnd() {
215 return showResultsBeforeEnd;
216 }
217
218 void setMaxChoices(int maxChoices) throws PollFormatException {
219 if (maxChoices < 1 || maxChoices > options.length) throw new PollFormatException();
220 this.maxChoices = maxChoices;
221 node.setProperty("poll_max_choices", maxChoices > 1 ? String.valueOf(maxChoices) : null);
222 }
223
224 void setEndDate(Date endDate) {
225 this.endDate = endDate;
226 node.setProperty("poll_end_date", endDate!=null ? String.valueOf(endDate.getTime()) : null);
227 }
228
229 void setAllowVoteChange(boolean allowVoteChange) {
230 node.setProperty("poll_allow_vote_change", allowVoteChange ? null : "false");
231 this.allowVoteChange = allowVoteChange;
232 }
233
234 void setShowResultsBeforeVote(boolean showResultsBeforeVote) {
235 node.setProperty("poll_show_results_before_vote", showResultsBeforeVote ? null : "false");
236 this.showResultsBeforeVote = showResultsBeforeVote;
237 }
238
239 void setShowResultsBeforeEnd(boolean showResultsBeforeEnd) {
240 node.setProperty("poll_show_results_before_end", showResultsBeforeEnd ? null : "false");
241 this.showResultsBeforeEnd = showResultsBeforeEnd;
242 }
243
244 public static class PollFormatException extends ModelException {
245 public PollFormatException() {
246 super(name("invalid_poll_format"), "Invalid poll parameters.");
247 }
248 }
249
250 public static class PollEditException extends ModelException {
251 public PollEditException() {
252 super(name("poll_edit_disallowed"), "You cannot modify this poll.");
253 }
254 }
255
256 public static class PollVoteException extends ModelException {
257 public PollVoteException() {
258 super(name("invalid_vote_attempt"), "Invalid voting attempt.");
259 }
260 }
261
262 }