Mercurial Hosting > nabble
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 } |