Merge lp:~acoconut/systers/flexible_essays into lp:systers
- flexible_essays
- Merge into stable
Status: | Superseded |
---|---|
Proposed branch: | lp:~acoconut/systers/flexible_essays |
Merge into: | lp:systers |
Diff against target: |
514 lines (+108/-81) 3 files modified
Mailman/Cgi/listinfo.py (+19/-6) Mailman/DlistUtils.py (+88/-69) bin/rmlist (+1/-6) |
To merge this branch: | bzr merge lp:~acoconut/systers/flexible_essays |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Robin J | Needs Fixing | ||
Review via email: mp+111405@code.launchpad.net |
This proposal has been superseded by a proposal from 2012-06-26.
Commit message
Description of the change
After week 1. You can manually change the questions in the pck file and the program reads the dictionary and displays the questions and the boxes.
Ana Cutillas (acoconut) wrote : | # |
> Review: Needs Fixing
>
> A suggestion for the future: when you put in a syslog statement, put in
> some identifying text, preferably the file that the message came from and
> what the data is. e.g.,
>
> syslog('info', "listinfo.py: essay question data for question %d = %s",
> i, mlist.questions
>
Mmm... I thought I had gotten rid of all the syslog statements, I was just
using them for my own testing purposes.
>
> In listinfo.py
>
> I'm confused by your parameters --can you remind me what the datastructure
> is for mlist.questions (what the columns are? I don't understand how you
> can do things with mlist.questions
> worked "by accident". )
>
[{1: ['talk about yourself', 'talk', 'largebox', 300, 'top']}, {2: ['Are
you a woman?', 'woman', 'checkbox', 0, 'bottom']}]
So basically:
[{question_number: ['question description', 'short version of question',
'type of box', 'size of box', 'position']}]
Why do you think this works by accident?
>
> I believe that mailman coding style requires 80 column line lengths. Can
> you shorten the long lines? (you may need to add some extra parens to make
> python understand that your new lines are continuation lines).
>
Ok, I will. There are some files in the systers folders that have very long
lines too, should I shorten those too? I mean code that I didn't write but
has very long lines.
>
> For things you are planning to do later (even if later is in the
> indefinite future, please start the comment with:
> #TODO (your name):
> that way it's easy to grep the code and find things you left for later.
>
> As best I can tell, you didn't actually make any changes to DlistUtils.py.
> Is that correct? If not, can you point out the places you made changes
> (it looks like these were the changes to fix our nasty lower case bug;
> maybe you had to import that file onto your branch?)
>
I only modified listinfo.py for the changes for the first week.
>
> Where do you define mlist.questions? (presumably in MailList.py, but why
> wasn't that included in your merge?) If you just manually created a
> mailing list with questions, please put that in the description of the
> change, showing exactly what is in that faked data structure.
>
mlist.questions was something that mailman was already using. It used to
get the one question from the pickle file, now it gets the data structure I
posted earlier.
> Use the description of the change to tell your reviewers the things they
> need to know to understand this code (like the mlist.questions data
> structure)
>
>
> Please, let me know if all this made or not sense and I'll make the
changes and resubmit .
> --
> https:/
> You are the owner of lp:~acoconut/systers/flexible_essays.
>
Robin J (robin-jeffries) wrote : | # |
1. It's fine to leave the syslog statements in (you can make a grep for them at the end of the summer). If they happen to make it into production, we turn DEBUG off there, so there is no harm. And you never know when a bug will come back to you
2. For the way you march down the mlist.questions data structure, I don't understand how you got it to work. If I understand it correctly, given
[{1: ['talk about yourself', 'talk', 'largebox', 300, 'top']}, {2: ['Are
you a woman?', 'woman', 'checkbox', 0, 'bottom']}]
your tests are for mlist.questions
the first time through that is mlist.questions
The next time through it is mlist.questions
(also, I missed this earlier. It would be better code to have your loop statement in line 12 in the diff be
for question in mlist.questions:
(range has to take that number an convert it to a location in the data structure, and this just marches down the data structure)
If you do that, then the test becomes something like
if question[1][2] ==...
(see how this is clearer? You could make it even clearer by making this a named structure (where you might have question.boxtype for the above), but for the small number of times you are going to reference it, it may not be worth it. But we may want to revisit this when we see how complex the admin UI is and how much improvement in clarity it gives)
3. For the updating of mlist.questions. I understand more now, but I think there is going to be an issue when you do the admin GUI -- this is not where things that are changed in the admin gui are stored (they are not part of mlist). This is not something you introduced, but it is something you will need to correct when you get to doing the admin GUI for this. Let's leave that issue until later.
Ana Cutillas (acoconut) wrote : | # |
Yes, I see what you meant about the for loop and I just got done fixing it.
I had to add an index though, I'm going to push the new version so that you
can see it. I couldn't figure out a way of doing it without an index.
As for the lines length, there are lines a lot longer that I didn't write.
I made mine shorter, let me know if I should change the ones I didn't write
too.
Thanks Robin! I love learning little things like the for loop thing. :)
On Tue, Jun 26, 2012 at 7:26 AM, Robin J <email address hidden> wrote:
> 1. It's fine to leave the syslog statements in (you can make a grep for
> them at the end of the summer). If they happen to make it into production,
> we turn DEBUG off there, so there is no harm. And you never know when a
> bug will come back to you
>
> 2. For the way you march down the mlist.questions data structure, I don't
> understand how you got it to work. If I understand it correctly, given
>
> [{1: ['talk about yourself', 'talk', 'largebox', 300, 'top']}, {2: ['Are
> you a woman?', 'woman', 'checkbox', 0, 'bottom']}]
>
> your tests are for mlist.questions
>
> the first time through that is mlist.questions
> the diff) -- that would be 'talk' above.)
>
> The next time through it is mlist.questions
> exist, right? shouldn't your test (and other items) be
> mlist.questions
>
> (also, I missed this earlier. It would be better code to have your loop
> statement in line 12 in the diff be
> for question in mlist.questions:
> (range has to take that number an convert it to a location in the data
> structure, and this just marches down the data structure)
>
> If you do that, then the test becomes something like
> if question[1][2] ==...
>
> (see how this is clearer? You could make it even clearer by making this a
> named structure (where you might have question.boxtype for the above), but
> for the small number of times you are going to reference it, it may not be
> worth it. But we may want to revisit this when we see how complex the
> admin UI is and how much improvement in clarity it gives)
>
> 3. For the updating of mlist.questions. I understand more now, but I
> think there is going to be an issue when you do the admin GUI -- this is
> not where things that are changed in the admin gui are stored (they are not
> part of mlist). This is not something you introduced, but it is something
> you will need to correct when you get to doing the admin GUI for this.
> Let's leave that issue until later.
>
> --
> https:/
> You are the owner of lp:~acoconut/systers/flexible_essays.
>
- 84. By Ana Cutillas <email address hidden>
-
Fixed the for loop that iterates through the list of questions, the
lines' length and other format issues.
Robin J (robin-jeffries) wrote : | # |
That's what code reviews are for.
I will look at the changed code as soon as I can, but I have out of town
guests tonight, and I don't know if I can steal some cycles from work or
not.
Robin
On Tue, Jun 26, 2012 at 10:34 AM, Ana Cutillas <email address hidden> wrote:
> Yes, I see what you meant about the for loop and I just got done fixing it.
> I had to add an index though, I'm going to push the new version so that you
> can see it. I couldn't figure out a way of doing it without an index.
>
> As for the lines length, there are lines a lot longer that I didn't write.
> I made mine shorter, let me know if I should change the ones I didn't write
> too.
>
> Thanks Robin! I love learning little things like the for loop thing. :)
>
> On Tue, Jun 26, 2012 at 7:26 AM, Robin J <email address hidden> wrote:
>
> > 1. It's fine to leave the syslog statements in (you can make a grep for
> > them at the end of the summer). If they happen to make it into
> production,
> > we turn DEBUG off there, so there is no harm. And you never know when a
> > bug will come back to you
> >
> > 2. For the way you march down the mlist.questions data structure, I
> don't
> > understand how you got it to work. If I understand it correctly, given
> >
> > [{1: ['talk about yourself', 'talk', 'largebox', 300, 'top']}, {2: ['Are
> > you a woman?', 'woman', 'checkbox', 0, 'bottom']}]
> >
> > your tests are for mlist.questions
> >
> > the first time through that is mlist.questions
> > the diff) -- that would be 'talk' above.)
> >
> > The next time through it is mlist.questions
> > exist, right? shouldn't your test (and other items) be
> > mlist.questions
> >
> > (also, I missed this earlier. It would be better code to have your loop
> > statement in line 12 in the diff be
> > for question in mlist.questions:
> > (range has to take that number an convert it to a location in the data
> > structure, and this just marches down the data structure)
> >
> > If you do that, then the test becomes something like
> > if question[1][2] ==...
> >
> > (see how this is clearer? You could make it even clearer by making this
> a
> > named structure (where you might have question.boxtype for the above),
> but
> > for the small number of times you are going to reference it, it may not
> be
> > worth it. But we may want to revisit this when we see how complex the
> > admin UI is and how much improvement in clarity it gives)
> >
> > 3. For the updating of mlist.questions. I understand more now, but I
> > think there is going to be an issue when you do the admin GUI -- this is
> > not where things that are changed in the admin gui are stored (they are
> not
> > part of mlist). This is not something you introduced, but it is
> something
> > you will need to correct when you get to doing the admin GUI for this.
> > Let's leave that issue until later.
> >
> > --
> >
> https:/
> > You are the owner of lp:~acoconut/systers/flexible_essays.
> >
>
> --
> https:/
> You are reviewing the pro...
- 85. By Ana Cutillas <email address hidden>
-
Changed the data structure to store the questions. Now it looks like:
[['Talk about yourself', 'talk', 'largebox', 300, 'top'], ['Are you a woman?', 'woman', 'checkbox', 0, 'bottom']]
- 86. By Ana Cutillas <email address hidden>
-
Changed the name of the variable questions to html_questions.
- 87. By Ana Cutillas <email address hidden>
-
Added changes to the DlistUtils.py file to handle the database
operations to the new table form_question. - 88. By Ana Cutillas <email address hidden>
-
Added the database backend and the functionality to connect forms to the database.
- 89. By Ana Cutillas <email address hidden>
-
Made changes to the database and to the way we store the answers. Made
changes to the way we handle the information coming from the form. - 90. By Ana Cutillas <email address hidden>
-
Cleaned up listinfo.py
- 91. By Ana Cutillas <email address hidden>
-
Cleaned up.
- 92. By Ana Cutillas <email address hidden>
-
Cleaned up DlistUtils and changed the error message in subscribe. Added
comments. - 93. By Ana Cutillas <email address hidden>
-
Removed the unused function get_answer from DlistUtils.py
- 94. By Ana Cutillas <email address hidden>
-
Added changes to show the new essays in the pending subscriptions table.
Handle the possibility of a user trying to subscribe twice before the
subscription is reviewed. - 95. By Ana Cutillas <email address hidden>
-
Added the functionality to check that the answers aren't longer than
what the database can hold. - 96. By Ana Cutillas <email address hidden>
-
Added the error message saying that the user hasn't been subscribe to
the list when a user tries to subscribe with a pending subscription. - 97. By Ana Cutillas <email address hidden>
-
Made the changes suggested by Robin: concerning error messages and
asserting the size of the answers.Added the code to mark answers as accepted in the database when a user
is accepted. - 98. By Ana Cutillas <email address hidden>
-
Changed the logic in the checking of answers in subscribe.py
Cleaned up DlistUtils.py - 99. By Ana Cutillas <email address hidden>
-
Added support for setting answers to rejected in the database.
Unmerged revisions
- 99. By Ana Cutillas <email address hidden>
-
Added support for setting answers to rejected in the database.
- 98. By Ana Cutillas <email address hidden>
-
Changed the logic in the checking of answers in subscribe.py
Cleaned up DlistUtils.py - 97. By Ana Cutillas <email address hidden>
-
Made the changes suggested by Robin: concerning error messages and
asserting the size of the answers.Added the code to mark answers as accepted in the database when a user
is accepted. - 96. By Ana Cutillas <email address hidden>
-
Added the error message saying that the user hasn't been subscribe to
the list when a user tries to subscribe with a pending subscription. - 95. By Ana Cutillas <email address hidden>
-
Added the functionality to check that the answers aren't longer than
what the database can hold. - 94. By Ana Cutillas <email address hidden>
-
Added changes to show the new essays in the pending subscriptions table.
Handle the possibility of a user trying to subscribe twice before the
subscription is reviewed. - 93. By Ana Cutillas <email address hidden>
-
Removed the unused function get_answer from DlistUtils.py
- 92. By Ana Cutillas <email address hidden>
-
Cleaned up DlistUtils and changed the error message in subscribe. Added
comments. - 91. By Ana Cutillas <email address hidden>
-
Cleaned up.
- 90. By Ana Cutillas <email address hidden>
-
Cleaned up listinfo.py
Preview Diff
1 | === modified file 'Mailman/Cgi/listinfo.py' |
2 | --- Mailman/Cgi/listinfo.py 2009-08-14 15:41:17 +0000 |
3 | +++ Mailman/Cgi/listinfo.py 2012-06-26 17:39:24 +0000 |
4 | @@ -22,6 +22,7 @@ |
5 | import os |
6 | import cgi |
7 | |
8 | +from Mailman import DlistUtils |
9 | from Mailman import mm_cfg |
10 | from Mailman import Utils |
11 | from Mailman import MailList |
12 | @@ -36,7 +37,6 @@ |
13 | i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE) |
14 | |
15 | |
16 | - |
17 | |
18 | def main(): |
19 | parts = Utils.GetPathPieces() |
20 | if not parts: |
21 | @@ -62,7 +62,6 @@ |
22 | list_listinfo(mlist, language) |
23 | |
24 | |
25 | - |
26 | |
27 | def listinfo_overview(msg=''): |
28 | # Present the general listinfo overview |
29 | hostname = Utils.get_domain() |
30 | @@ -152,7 +151,6 @@ |
31 | print doc.Format() |
32 | |
33 | |
34 | - |
35 | |
36 | def list_listinfo(mlist, lang): |
37 | # Generate list specific listinfo |
38 | doc = HeadlessDocument() |
39 | @@ -190,9 +188,24 @@ |
40 | # If activated, the content and presence of questions and a field to answer them. Added by Systers. |
41 | try: |
42 | if mlist.essay_enabled: |
43 | - replacements['<mm-questions>'] = """<TR> |
44 | - <TD COLSPAN="3">""" + mlist.questions |
45 | - replacements['<mm-essay-box>'] = TextArea('essay', '', rows=8, cols=60).Format() + """ </TD></TR>"""# Added to support subscribe essays |
46 | + questions = [] # Added to support subscribe essays |
47 | + index = 1 |
48 | + for question in mlist.questions: |
49 | + questions.append("""<TR> |
50 | + <TD COLSPAN="3">""" + question[index][0] + """</TD>""") |
51 | + if (question[index][2] == 'smallbox'): |
52 | + questions.append("""<TD>""" + TextArea(question[index][1],\ |
53 | + '', rows=1, cols=60).Format() + """</TD></TR>""") |
54 | + elif (question[index][2] == 'largebox'): |
55 | + questions.append("""<TD>""" + TextArea(question[index][1], \ |
56 | + '', rows=8, cols=60).Format() + """</TD></TR>""") |
57 | + elif (question[index][2] == 'checkbox'): |
58 | + #TODO (Ana Cutillas): consider creating a class like TextArea for checkboxes? |
59 | + questions.append("""<TD><input type='checkbox' name='""" + \ |
60 | + question[index][1] + """' value ='""" + \ |
61 | + question[index][1] + """'></TD></TR>""") |
62 | + index = index + 1 |
63 | + replacements['<mm-questions>'] = ''.join(questions) |
64 | else: |
65 | replacements['<mm-questions>'] = '' |
66 | replacements['<mm-essay-box>'] = '' |
67 | |
68 | === modified file 'Mailman/DlistUtils.py' |
69 | --- Mailman/DlistUtils.py 2010-01-31 20:29:48 +0000 |
70 | +++ Mailman/DlistUtils.py 2012-06-26 17:39:24 +0000 |
71 | @@ -40,17 +40,17 @@ |
72 | if self == classObject: |
73 | if self.store == None:#for the case when same object is used for calling more than one functions |
74 | self.store = Store(self.database) |
75 | - result = f(self,*args) |
76 | + result = f(self, *args) |
77 | self.store.commit() |
78 | self.store.close() |
79 | self.store = None |
80 | else:#To handle the nesting issue |
81 | - result = f(self,*args) |
82 | + result = f(self, *args) |
83 | self.store.commit() |
84 | else:#for the case whenever a new object calls its decorated member function |
85 | classObject = self |
86 | self.store = Store(self.database) |
87 | - result = f(self,*args) |
88 | + result = f(self, *args) |
89 | self.store.commit() |
90 | self.store.close() |
91 | self.store = None |
92 | @@ -60,14 +60,14 @@ |
93 | #Define all the classes corresponding to the tables in the database |
94 | class Subscriber(object): |
95 | __storm_table__ = "subscriber" |
96 | - subscriber_id = Int(primary = True,default = AutoReload) |
97 | + subscriber_id = Int(primary = True, default = AutoReload) |
98 | mailman_key = Unicode() |
99 | preference = Int(default = 1) |
100 | format = Int(default = 3) |
101 | deleted = Bool(default = False) |
102 | suppress = Int(default = 0) |
103 | |
104 | - def __init__(self,mlist): |
105 | + def __init__(self, mlist): |
106 | self.mlist = mlist |
107 | self.database = getConn(mlist) |
108 | |
109 | @@ -76,11 +76,11 @@ |
110 | if addr == None: |
111 | return None |
112 | |
113 | - command = "result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(addr.lower(),'utf-8'))\na = [(subscriber.subscriber_id) for subscriber in result]\n" |
114 | + command = "result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(addr.lower(),'utf-8'))\na = [(subscriber.subscriber_id) for subscriber in result]\n" |
115 | if DEBUG_MODE: |
116 | syslog('info', "DlistUtils:(getSubscriber_id_raw)executing query:\n%s", command) |
117 | #storm recognizes unicode only |
118 | - result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(addr.lower(),"utf-8")) |
119 | + result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(addr,"utf-8")) |
120 | a = [(subscriber.subscriber_id) for subscriber in result] |
121 | if DEBUG_MODE: |
122 | syslog('info', 'value of a is: %s\n', a) |
123 | @@ -136,70 +136,70 @@ |
124 | @decfunc |
125 | def setDisable(self, member, flag): |
126 | """Disable/enable delivery based on mm_cfg.DisableDelivery""" |
127 | - command = "result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,'utf-8'))\noldval = [(subscriber.suppress) for subscriber in result]\n" |
128 | + command = "result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,'utf-8'))\noldval = [(subscriber.suppress) for subscriber in result]\n" |
129 | if DEBUG_MODE: |
130 | - syslog('info', 'DlistUtils(setDisable):Executing query:\n%s\n Member whoes suppress value is to be found \n %s', command,member) |
131 | - result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,"utf-8")) |
132 | + syslog('info', 'DlistUtils(setDisable):Executing query:\n%s\n Member whose suppress value is to be found \n %s', command, member) |
133 | + result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,"utf-8")) |
134 | oldval = [(subscriber.suppress) for subscriber in result] |
135 | if oldval == []: |
136 | if DEBUG_MODE: |
137 | syslog('info','oldval is an empty list.\nThis can happen either because of\n 1)Permission issues (Do a: bin/check_perms)\n 2)Inconsistency between database and pickle files (A user is in the database but not in pickle files or vice versa,Do a bin/find_problems.py)') |
138 | oldval = oldval[0] |
139 | if DEBUG_MODE: |
140 | - syslog('info','the value of oldval is %s:',oldval) |
141 | + syslog('info','the value of oldval is %s:', oldval) |
142 | |
143 | if flag: |
144 | newval = oldval | 1 # Disable delivery |
145 | else: |
146 | newval = oldval & ~1 # Enable delivery |
147 | if DEBUG_MODE: |
148 | - syslog('info','the value of newval is %s:',newval) |
149 | - command = "self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,'utf-8')).set(suppress = newval)\n" |
150 | + syslog('info','the value of newval is %s:', newval) |
151 | + command = "self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,'utf-8')).set(suppress = newval)\n" |
152 | if DEBUG_MODE: |
153 | syslog('info', 'DlistUtils(setDisable):Executing query:\n%s', command) |
154 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,"utf-8")).set(suppress = newval) |
155 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,"utf-8")).set(suppress = newval) |
156 | |
157 | @decfunc |
158 | def setDigest(self, member, flag): |
159 | """Disable/enable delivery based on user digest status""" |
160 | |
161 | - command = "result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,'utf-8'))\noldval = [(subscriber.suppress) for subscriber in result]\n" |
162 | + command = "result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,'utf-8'))\noldval = [(subscriber.suppress) for subscriber in result]\n" |
163 | if DEBUG_MODE: |
164 | syslog('info', 'DlistUtils(setDigest):Executing query:\n%s', command) |
165 | - result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,"utf-8")) |
166 | + result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,"utf-8")) |
167 | oldval = [(subscriber.suppress) for subscriber in result] |
168 | if oldval == []: |
169 | if DEBUG_MODE: |
170 | syslog('info','oldval is an empty list.\nThis can happen either because of\n 1)permission issues (Do a: bin/check_perms)\n 2)Inconsistency between database and pickle files (A user is in the database but not in pickle files or vice versa,Do a bin/find_problems.py)') |
171 | oldval = oldval[0] |
172 | if DEBUG_MODE: |
173 | - syslog('info','value of oldval %s:',oldval) |
174 | + syslog('info','value of oldval %s:', oldval) |
175 | |
176 | if flag: |
177 | newval = oldval | 2 # Suppress delivery (in favor of digests) |
178 | else: |
179 | newval = oldval & ~2 # Enable delivery (instead of digests) |
180 | |
181 | - command = "self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,'utf-8')).set(suppress = newval)\n" |
182 | + command = "self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,'utf-8')).set(suppress = newval)\n" |
183 | if DEBUG_MODE: |
184 | syslog('info', 'DlistUtils(setDigest):Executing query:\n%s', command) |
185 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,"utf-8")).set(suppress = newval) |
186 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,"utf-8")).set(suppress = newval) |
187 | |
188 | @decfunc |
189 | def changePreference(self, member, preference): |
190 | """Change a user's default preference for new threads.""" |
191 | - command = "self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,'utf-8')).set(preference = preference)\n" |
192 | + command = "self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,'utf-8')).set(preference = preference)\n" |
193 | if DEBUG_MODE: |
194 | syslog('info', 'DlistUtils(changePreference):Executing query:\n%s', command) |
195 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,"utf-8")).set(preference = preference) |
196 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,"utf-8")).set(preference = preference) |
197 | |
198 | @decfunc |
199 | def changeFormat(self, member, format): |
200 | """Change a user's preferred delivery format (plain text and/or html)""" |
201 | - command = "self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,'utf-8')).set(format = format)\n" |
202 | + command = "self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,'utf-8')).set(format = format)\n" |
203 | if DEBUG_MODE: |
204 | syslog('info', 'DlistUtils(changeFormat):Executing query:\n%s', command) |
205 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(member,"utf-8")).set(format = format) |
206 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(member,"utf-8")).set(format = format) |
207 | |
208 | ### We have to watch out for a tricky case (that actually happened): |
209 | ### User foo@bar.com changes her address to something already in the |
210 | @@ -207,32 +207,32 @@ |
211 | @decfunc |
212 | def changeAddress(self, oldaddr, newaddr): |
213 | """Change email address in SQL database""" |
214 | - #if DEBUG_MODE: |
215 | - #syslog('info', "Changing email address on %s from '%s' to '%s'", self.mlist.internal_name(), oldaddr, newaddr) |
216 | + if DEBUG_MODE: |
217 | + syslog('info', "Changing email address on %s from '%s' to '%s'", self.mlist.internal_name(), oldaddr, newaddr) |
218 | ## Check if newaddr is in sql database |
219 | - num_matches = self.store.find(Subscriber,Subscriber.mailman_key == unicode(newaddr,"utf-8")).count() |
220 | + num_matches = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(newaddr.lower(),"utf-8")).count() |
221 | |
222 | if num_matches > 1: |
223 | - #syslog('error', 'Multiple users with same key (%s): %s', self.mlist.internal_name(), newaddr) |
224 | + syslog('error', 'Multiple users with same key (%s): %s', self.mlist.internal_name(), newaddr) |
225 | return |
226 | if num_matches == 1: |
227 | self.mergeSubscribers(oldaddr, newaddr) |
228 | |
229 | - command = "num_matches = self.store.find(Subscriber,Subscriber.mailman_key == unicode(newaddr,'utf-8')).count()\nself.store.find(Subscriber,Subscriber.mailman_key == unicode(oldaddr,'utf-8')).set(mailman_key = unicode(newaddr,'utf-8'))\nself.store.find(Subscriber,Subscriber.mailman_key == unicode(newaddr,'utf-8')).set(deleted = False)\n" |
230 | + command = "num_matches = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(newaddr,'utf-8')).count()\nself.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(oldaddr,'utf-8')).set(mailman_key = unicode(newaddr,'utf-8'))\nself.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(newaddr.lower(),'utf-8')).set(deleted = False)\n" |
231 | if DEBUG_MODE: |
232 | syslog('info', 'DlistUtils(changeAddress):Executing query:\n%s', command) |
233 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(oldaddr,"utf-8")).set(mailman_key = unicode(newaddr,"utf-8")) |
234 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(oldaddr,"utf-8")).set(mailman_key = unicode(newaddr,"utf-8")) |
235 | self.store.commit() |
236 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(newaddr,"utf-8")).set(deleted = False) |
237 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(newaddr.lower(),"utf-8")).set(deleted = False) |
238 | |
239 | @decfunc |
240 | def unsubscribeFromList(self, key): |
241 | """Indicate that a user has unsubscribed by setting the deleted flag in the subscriber table.""" |
242 | |
243 | - command = "self.store.find(Subscriber,Subscriber.mailman_key == unicode(key,'utf-8')).set(deleted = True)\nself.store.find(Alias,Alias.subscriber_id == subscriber_id).remove()\n" |
244 | + command = "self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key,'utf-8')).set(deleted = True)\nself.store.find(Alias,Alias.subscriber_id == subscriber_id).remove()\n" |
245 | if DEBUG_MODE: |
246 | syslog('info', 'DlisUtils(unsubscribeFromList):Executing query:\n%s', command) |
247 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(key,"utf-8")).set(deleted = True) |
248 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key,"utf-8")).set(deleted = True) |
249 | # get the subscriber id from the mailman_key & delete all aliases |
250 | subscriber_id = self.getSubscriber_id_raw(key) |
251 | |
252 | @@ -245,20 +245,27 @@ |
253 | def subscribeToList(self, key): |
254 | """Add a member to the subscriber database, or change the record from deleted if it was already present.""" |
255 | |
256 | - command = "count = (self.store.find(Subscriber,Subscriber.mailman_key == unicode(key,'utf-8'))).count()\n" |
257 | + command = "count = (self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key.lower(),'utf-8'))).count()\n" |
258 | if DEBUG_MODE: |
259 | syslog('info', 'DlistUtils(subscribeToList):Executing query:\n%s', command) |
260 | # First see if member is subscribed with deleted field = false |
261 | - count = (self.store.find(Subscriber,Subscriber.mailman_key == unicode(key,"utf-8"))).count() |
262 | + count = (self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key.lower(),"utf-8"))).count() |
263 | |
264 | if count: |
265 | - command = "self.store.find(Subscriber,Subscriber.mailman_key == unicode(key,'utf-8')).set(deleted = False)" |
266 | + command = "self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key.lower(),'utf-8')).set(deleted = False)" |
267 | if DEBUG_MODE: |
268 | syslog('info', 'DlistUtils(subscribeToList):Executing query:\n%s', command) |
269 | - self.store.find(Subscriber,Subscriber.mailman_key == unicode(key,"utf-8")).set(deleted = False) |
270 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key.lower(),"utf-8")).set(deleted = False) |
271 | + |
272 | + result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key.lower(),"utf-8")) |
273 | + Email = [(subscriber.mailman_key) for subscriber in result] |
274 | + Email = Email[0] |
275 | + if Email != key: #That is if one was in lowercase and other in uppercase then update mailman_key with case sensitivity same as key |
276 | + self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(key.lower(),"utf-8")).set(mailman_key = unicode(key,"utf-8")) |
277 | + |
278 | else: |
279 | # format is text-only (1) by default |
280 | - command = "subscriber = self.store.add(Subscriber())\nsubscriber.mailman_key = unicode(key,'utf-8')\nsubscriber.preference = 1\nsubscriber.deleted = False\nsubscriber.format = 1\nsubscriber.suppress = 0" |
281 | + command = "subscriber = self.store.add(Subscriber())\nmailman_key = unicode(key,'utf-8')\npreference = 1\ndeleted = False\nformat = 1\nsuppress = 0" |
282 | if DEBUG_MODE: |
283 | syslog('info', 'DlistUtils(subscribeToList)Executing query:\n%s', command) |
284 | self.mailman_key = unicode(key,"utf-8") |
285 | @@ -273,12 +280,12 @@ |
286 | # use the original subscriber id as the ID going forward |
287 | if DEBUG_MODE: |
288 | syslog('info', 'Executing commands of mergeSubscribers:') |
289 | - result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(oldaddr,"utf-8")) |
290 | + result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(oldaddr,"utf-8")) |
291 | new_id = [(subscriber.subscriber_id) for subscriber in result] |
292 | new_id = new_id[0] |
293 | if DEBUG_MODE: |
294 | syslog('info', 'the value of new_id: %s', new_id) |
295 | - result = self.store.find(Subscriber,Subscriber.mailman_key == unicode(newaddr,"utf-8")) |
296 | + result = self.store.find(Subscriber,Subscriber.mailman_key.lower() == unicode(newaddr.lower(),"utf-8")) |
297 | obsolete_id = [(subscriber.subscriber_id) for subscriber in result] |
298 | obsolete_id = obsolete_id[0] |
299 | if DEBUG_MODE: |
300 | @@ -291,13 +298,13 @@ |
301 | |
302 | class Message(object): |
303 | __storm_table__ = "message" |
304 | - message_id = Int(primary = True,default = AutoReload) |
305 | + message_id = Int(primary = True, default = AutoReload) |
306 | sender_id = Int() |
307 | - subscriber = Reference(sender_id,Subscriber.subscriber_id) |
308 | + subscriber = Reference(sender_id, Subscriber.subscriber_id) |
309 | subject = Unicode() |
310 | thread_id = Int() |
311 | |
312 | - def __init__(self,mlist): |
313 | + def __init__(self, mlist): |
314 | self.mlist = mlist |
315 | self.database = getConn(mlist) |
316 | |
317 | @@ -314,7 +321,7 @@ |
318 | threadID = -1 |
319 | command = "message = self.store.add(Message())\nmessage.sender_id = senderID\nmessage.thread_id = threadID\nmessage.subject = unicode(subject,'utf-8')\nmessageID = self.store.find(Message).max(Message.message_id)\n" |
320 | if DEBUG_MODE: |
321 | - syslog('info','DlistUtils:(createMessage)executing query:\n%s',command) |
322 | + syslog('info','DlistUtils:(createMessage)executing query:\n%s', command) |
323 | #message_id has autoreload set,its value will be serially updated in database |
324 | self.sender_id = senderID |
325 | self.thread_id = threadID |
326 | @@ -322,19 +329,19 @@ |
327 | self.store.add(self) |
328 | messageID = self.store.find(Message).max(Message.message_id) |
329 | if DEBUG_MODE: |
330 | - syslog('info','Result of query(messageID) is: %s\n',messageID) |
331 | + syslog('info','Result of query(messageID) is: %s\n', messageID) |
332 | return messageID |
333 | |
334 | class Thread(object): |
335 | __storm_table__ = "thread" |
336 | - thread_id = Int(primary = True,default = AutoReload) |
337 | + thread_id = Int(primary = True, default = AutoReload) |
338 | thread_name = Unicode() |
339 | base_message_id = Int() |
340 | - message = Reference(base_message_id,Message.message_id) |
341 | + message = Reference(base_message_id, Message.message_id) |
342 | status = Int(default = 0) |
343 | parent = Int() |
344 | |
345 | - def __init__(self,mlist): |
346 | + def __init__(self, mlist): |
347 | self.mlist = mlist |
348 | self.database = getConn(mlist) |
349 | |
350 | @@ -347,7 +354,7 @@ |
351 | senderID = subscriber.getSubscriber_id(msg, msgdata, safe=1, loose=1) |
352 | command = "thread = self.store.add(Thread())\nthread.base_message_id = msgdata['message_id']\nthreadID = self.store.find(Thread).max(Thread.thread_id)\nself.store.find(Message,Message.message_id == msgdata['message_id']).set(thread_id = threadID)\n" |
353 | if DEBUG_MODE: |
354 | - syslog('info','DlistUtils:(createThread)executing query:\n%s',command) |
355 | + syslog('info','DlistUtils:(createThread)executing query:\n%s', command) |
356 | self.base_message_id = msgdata['message_id'] |
357 | self.store.add(self) |
358 | threadID = self.store.find(Thread).max(Thread.thread_id) |
359 | @@ -370,7 +377,7 @@ |
360 | threadBase = threadBase[:13] |
361 | command = "num = self.store.find(Thread,Thread.thread_name == unicode(threadBase,'utf-8')).count()\nself.store.find(Thread,Thread.thread_id == threadID).set(thread_name = threadName)\n" |
362 | if DEBUG_MODE: |
363 | - syslog('info','DlistUtils:(createThread)executing query:\n%s',command) |
364 | + syslog('info','DlistUtils:(createThread)executing query:\n%s', command) |
365 | # If the threadBase is not unique, make threadBase unique by appending a number |
366 | num = self.store.find(Thread,Thread.thread_name.like(unicode(threadBase + "%","utf-8"))).count() |
367 | if not num: |
368 | @@ -405,26 +412,24 @@ |
369 | msg['To'] = '%s+%s@%s' % (self.mlist.internal_name(), |
370 | name, |
371 | self.mlist.host_name) |
372 | - for i in (1,2): |
373 | + for i in (1, 2): |
374 | # different footers for different prefs, so we need to queue separately |
375 | if(i==1): |
376 | #For condition where preference = True |
377 | pref=True |
378 | - # command = "lists = [(subscriber.mailman_key.encode('utf-8')) for subscriber in result_new_sql]\n" |
379 | - # if DEBUG_MODE: |
380 | - # syslog('info', 'DlistUtils:(newThread)executing query:\n%sfor pref = true\n', command) |
381 | + if DEBUG_MODE: |
382 | + syslog('info', 'DlistUtils:(newThread)executing query:\nfor pref = true\n\n') |
383 | if(i==2): |
384 | #For condition where preference = False |
385 | pref=False |
386 | - # command = "lists = [(subscriber.mailman_key.encode('utf-8')) for subscriber in result_new_sql]\n" |
387 | - # if DEBUG_MODE: |
388 | - # syslog('info', 'DlistUtils:(newThread)executing query:\n%sfor pref = false\n', command) |
389 | + if DEBUG_MODE: |
390 | + syslog('info', 'DlistUtils:(newThread)executing query:\nfor pref = false\n\n') |
391 | |
392 | #Execute a SELECT statement, to find the list of matching subscribers. |
393 | result_new_sql = self.store.find(Subscriber,And(Subscriber.preference == pref,Subscriber.deleted == False,Subscriber.suppress == 0)) |
394 | lists = [(subscriber.mailman_key.encode('utf-8')) for subscriber in result_new_sql] |
395 | if DEBUG_MODE: |
396 | - syslog('info', 'value of lists: %s\n', lists) |
397 | + syslog('info','value of lists: %s\n', lists) |
398 | self.email_recipients(msg, msgdata, lists, pref) |
399 | |
400 | # Make original message go to nobody (but be archived) |
401 | @@ -514,12 +519,12 @@ |
402 | override = Override(self.mlist) |
403 | override.override(msg, msgdata, 0) |
404 | |
405 | - def alphanumericOnly(self,s): |
406 | + def alphanumericOnly(self, s): |
407 | """Filter any non-letter characters from a string""" |
408 | result = [letter for letter in s if letter in string.ascii_letters or letter in string.digits] |
409 | return string.join(result, '') |
410 | |
411 | - def subjectToName(self,subject, threadID): |
412 | + def subjectToName(self, subject, threadID): |
413 | """Return a lower-case name for a new thread based on the subject, if present, or on the threadID""" |
414 | result = None |
415 | |
416 | @@ -589,9 +594,9 @@ |
417 | __storm_table__ = "alias" |
418 | pseudonym = Unicode(primary = True) |
419 | subscriber_id = Int() |
420 | - subscriber = Reference(subscriber_id,Subscriber.subscriber_id) |
421 | + subscriber = Reference(subscriber_id, Subscriber.subscriber_id) |
422 | |
423 | - def __init__(self,mlist): |
424 | + def __init__(self, mlist): |
425 | self.mlist = mlist |
426 | self.database = getConn(mlist) |
427 | |
428 | @@ -604,8 +609,8 @@ |
429 | syslog('info', 'DlistUtils(canonicalize_sender)Executing query:\n%s', command) |
430 | |
431 | for alias in aliases: |
432 | - #if DEBUG_MODE: |
433 | - #syslog('info', 'Checking if <%s> is an alias', alias) |
434 | + if DEBUG_MODE: |
435 | + syslog('info', 'Checking if <%s> is an alias', alias) |
436 | result = self.store.find((Subscriber,Alias),And(Alias.pseudonym == unicode(alias,'utf-8'),Subscriber.subscriber_id == Alias.subscriber_id)) |
437 | lists = [(subscriber.mailman_key.encode('utf-8')) for (subscriber,alias) in result] |
438 | |
439 | @@ -654,12 +659,12 @@ |
440 | __storm_table__ = "override" |
441 | __storm_primary__ = "subscriber_id", "thread_id" |
442 | subscriber_id = Int() |
443 | - subscriber = Reference(subscriber_id,Subscriber.subscriber_id) |
444 | + subscriber = Reference(subscriber_id, Subscriber.subscriber_id) |
445 | thread_id = Int() |
446 | - thread = Reference(thread_id,Thread.thread_id) |
447 | + thread = Reference(thread_id, Thread.thread_id) |
448 | preference = Int() |
449 | |
450 | - def __init__(self,mlist): |
451 | + def __init__(self, mlist): |
452 | self.mlist = mlist |
453 | self.database = getConn(mlist) |
454 | |
455 | @@ -709,10 +714,9 @@ |
456 | |
457 | return 1 |
458 | |
459 | - def overrideURL(self,list_name, host_name, thread_reference, preference): |
460 | + def overrideURL(self, list_name, host_name, thread_reference, preference): |
461 | return 'http://%s/mailman/options/%s?override=%s&preference=%d' % (host_name, list_name, thread_reference, preference) |
462 | |
463 | - |
464 | #Functions Independent of the database tables in DlistUtils |
465 | |
466 | def GetEmailAddresses(mlist, subscribers): |
467 | @@ -752,13 +756,22 @@ |
468 | |
469 | def _create_database(name): |
470 | """Create a database. This requires us to not be in a transaction.""" |
471 | - conn = pgdb.connect(host='localhost', database='postgres',user='mailman', password='mailman') |
472 | + conn = pgdb.connect(host='localhost', database='postgres', user='mailman', password='mailman') |
473 | old_iso_lvl = conn.isolation_level |
474 | conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) |
475 | cursor = conn.cursor() |
476 | cursor.execute('create database "%s"' % name) |
477 | conn.set_isolation_level(old_iso_lvl) |
478 | |
479 | +def _remove_database(name): |
480 | + """Remove a database. This requires us to not be in a transaction.""" |
481 | + conn = pgdb.connect(host='localhost', database='postgres', user='mailman', password='mailman') |
482 | + old_iso_lvl = conn.isolation_level |
483 | + conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) |
484 | + cursor = conn.cursor() |
485 | + cursor.execute('DROP DATABASE "%s"' % name) |
486 | + conn.set_isolation_level(old_iso_lvl) |
487 | + |
488 | def executeSQL(mlist, commands): |
489 | """Execute a sequence of SQL commands that create tables in the database.""" |
490 | database = getConn(mlist) |
491 | @@ -834,3 +847,9 @@ |
492 | mlist.Save() |
493 | if alreadyLocked == 0: |
494 | mlist.Unlock() |
495 | + |
496 | +def remove_dlist(listname): |
497 | + """ Deletes the corresponding postgres database and tables.""" |
498 | + _remove_database(listname) |
499 | + if DEBUG_MODE: |
500 | + syslog('info', "Database %s removed\n", listname) |
501 | |
502 | === modified file 'bin/rmlist' |
503 | --- bin/rmlist 2009-07-31 10:49:01 +0000 |
504 | +++ bin/rmlist 2012-06-26 17:39:24 +0000 |
505 | @@ -152,12 +152,7 @@ |
506 | |
507 | # Remove the database in PostgreSQL if it was a dynamic list. Added by Systers. |
508 | try: |
509 | - conn = DlistUtils.getConn(None) |
510 | - old_iso_lvl = conn.isolation_level |
511 | - conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) |
512 | - cursor = conn.cursor() |
513 | - cursor.execute('DROP DATABASE "%s"' % listname) |
514 | - conn.set_isolation_level(old_iso_lvl) |
515 | + DlistUtils.remove_dlist(listname) |
516 | except: |
517 | syslog('error', 'Tried to remove the database for %s, no such database (ok if it was a non dlist). If it was a dlist, the postgreSQL database for this list needs to be removed manually.' % listname) |
518 |
A suggestion for the future: when you put in a syslog statement, put in some identifying text, preferably the file that the message came from and what the data is. e.g.,
syslog('info', "listinfo.py: essay question data for question %d = %s", i, mlist.questions [i][i+1] [2])
In listinfo.py
I'm confused by your parameters --can you remind me what the datastructure is for mlist.questions (what the columns are? I don't understand how you can do things with mlist.questions [i][i+1] [0] etc. I think this must have worked "by accident". )
I believe that mailman coding style requires 80 column line lengths. Can you shorten the long lines? (you may need to add some extra parens to make python understand that your new lines are continuation lines).
For things you are planning to do later (even if later is in the indefinite future, please start the comment with:
#TODO (your name):
that way it's easy to grep the code and find things you left for later.
As best I can tell, you didn't actually make any changes to DlistUtils.py. Is that correct? If not, can you point out the places you made changes (it looks like these were the changes to fix our nasty lower case bug; maybe you had to import that file onto your branch?)
Where do you define mlist.questions? (presumably in MailList.py, but why wasn't that included in your merge?) If you just manually created a mailing list with questions, please put that in the description of the change, showing exactly what is in that faked data structure.
Use the description of the change to tell your reviewers the things they need to know to understand this code (like the mlist.questions data structure)