Changeset e0632f6 for asadb/groups
- Timestamp:
- Sep 10, 2012, 5:02:55 AM (13 years ago)
- Branches:
- master, space-access, stable, stage
- Children:
- ab17953
- Parents:
- 3af5d74 (diff), 51b384a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Alex Dehnert <adehnert@…> (09/10/12 05:02:55)
- git-committer:
- Alex Dehnert <adehnert@…> (09/10/12 05:02:55)
- Location:
- asadb/groups
- Files:
-
- 1 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
asadb/groups/gather_constitutions.py
rfb1c047 rc632b1c 12 12 import datetime 13 13 import subprocess 14 15 import django.contrib.auth.models 16 import reversion 14 17 15 18 import groups.models … … 71 74 print "%4d\t%s" % (len(gs), code, ) 72 75 76 def list_constitutions(): 77 constitutions = groups.models.GroupConstitution.objects.all() 78 for const in constitutions: 79 if const.dest_file: print const.dest_file 80 73 81 if __name__ == '__main__': 74 82 if len(sys.argv) == 1 or sys.argv[1] == "gather": 75 additions, changed = gather_constitutions() 83 with reversion.create_revision(): 84 additions, changed = gather_constitutions() 85 importer = django.contrib.auth.models.User.objects.get(username='gather-constitutions@SYSTEM', ) 86 reversion.set_user(importer) 87 reversion.set_comment("gather constitutions") 88 76 89 update_repo(additions, changed) 77 90 elif sys.argv[1] == "webstat": 78 91 webstat() 92 elif sys.argv[1] == "list": 93 list_constitutions() 79 94 else: 80 95 raise NotImplementedError -
asadb/groups/models.py
r3af5d74 re0632f6 11 11 import re 12 12 import shutil 13 import urlparse 13 14 import urllib 15 import urllib2 14 16 15 17 import settings 18 19 import mit 16 20 17 21 # Create your models here. … … 34 38 group_funding = models.ForeignKey('GroupFunding', null=True, blank=True, db_index=True, ) 35 39 website_url = models.URLField() 36 constitution_url = models.CharField(max_length=200, blank=True )40 constitution_url = models.CharField(max_length=200, blank=True, validators=[mit.UrlOrAfsValidator]) 37 41 meeting_times = models.TextField(blank=True) 38 42 advisor_name = models.CharField(max_length=100, blank=True) … … 137 141 failure_reason = models.CharField(max_length=100, blank=True, default="") 138 142 143 def record_failure(self, msg): 144 now = datetime.datetime.now() 145 if not self.failure_date: 146 self.failure_date = now 147 self.status_msg = msg 148 self.failure_reason = self.status_msg 149 self.save() 150 151 def record_success(self, msg, updated): 152 now = datetime.datetime.now() 153 if updated: 154 self.last_update = now 155 self.status_msg = msg 156 self.last_download = now 157 self.failure_date = None 158 self.failure_reason = "" 159 self.save() 160 139 161 def update(self, ): 140 162 url = self.source_url … … 142 164 old_success = (self.failure_date is None) 143 165 if url: 144 url_opener = urllib.FancyURLopener()145 now = datetime.datetime.now()166 # Fetch the file 167 error_msg = None 146 168 try: 147 tmp_path, headers = url_opener.retrieve(url) 169 new_mimetype = None 170 if url.startswith('/afs/') or url.startswith('/mit/'): 171 new_fp = open(url, 'rb') 172 else: 173 new_fp = urllib2.urlopen(url) 174 if new_fp.info().getheader('Content-Type'): 175 new_mimetype = new_fp.info().gettype() 176 177 new_data = new_fp.read() 178 new_fp.close() 179 except urllib2.HTTPError, e: 180 error_msg = "HTTPError: %s %s" % (e.code, e.msg) 181 except urllib2.URLError, e: 182 error_msg = "URLError: %s" % (e.reason) 148 183 except IOError: 149 self.failure_date = now 150 self.save() 151 success = False 152 self.status_msg = "retrieval failed" 153 self.failure_reason = self.status_msg 154 return (success, self.status_msg, old_success, ) 155 if tmp_path == url: 156 mover = shutil.copyfile 157 else: 158 mover = shutil.move 159 save_filename = self.compute_filename(tmp_path, headers, ) 160 dest_path = self.path_from_filename(self.dest_file) 161 if save_filename != self.dest_file: 162 if self.dest_file: os.remove(dest_path) 163 mover(tmp_path, self.path_from_filename(save_filename)) 164 self.dest_file = save_filename 165 self.last_update = now 166 self.status_msg = "new path" 167 else: 168 if filecmp.cmp(tmp_path, dest_path, shallow=False, ): 169 self.status_msg = "no change" 184 error_msg = "IOError" 185 except ValueError, e: 186 if e.args[0].startswith('unknown url type'): 187 error_msg = "unknown url type" 170 188 else: 171 # changed172 mover(tmp_path, dest_path)173 self.last_update = now174 self.status_msg = "updated in place"175 self.last_download = now 176 self.failure_date = None177 self.failure_reason = ""178 self.save()189 raise 190 if error_msg: 191 self.record_failure(error_msg) 192 return (False, self.status_msg, old_success, ) 193 194 # At this point, failures are our fault, not the group's. 195 # We can let any errors bubble all the way up, rather than 196 # trying to catch and neatly record them 179 197 success = True 198 199 # Find a destination, and how to put it there 200 old_path = self.path_from_filename(self.dest_file) 201 new_filename = self.compute_filename(url, new_mimetype, ) 202 203 # Process the update 204 if new_filename != self.dest_file: # new filename 205 if self.dest_file: 206 if os.path.exists(old_path): 207 os.remove(old_path) 208 else: 209 print "Warning: %s doesn't exist, but is referenced by dest_file" % (old_path, ) 210 self.dest_file = new_filename 211 new_path = self.path_from_filename(new_filename) 212 with open(new_path, 'wb') as fp: 213 fp.write(new_data) 214 self.record_success("new path", updated=True) 215 else: # old filename 216 with open(old_path, 'rb') as old_fp: 217 old_data = old_fp.read() 218 if old_data == new_data: # unchanged 219 self.record_success("no change", updated=False) 220 else: # changed 221 with open(old_path, 'wb') as fp: 222 fp.write(new_data) 223 self.record_success("updated in place", updated=True) 224 180 225 else: 226 self.record_failure("no url") 181 227 success = False 182 self.status_msg = "no url" 183 self.failure_reason = self.status_msg 228 184 229 return (success, self.status_msg, old_success, ) 185 230 186 def compute_filename(self, tmp_path, headers,):231 def compute_filename(self, url, mimetype): 187 232 slug = self.group.slug() 188 basename, fileext = os.path.splitext(tmp_path) 233 known_ext = set([ 234 '.pdf', 235 '.ps', 236 '.doc', 237 '.rtf', 238 '.html', 239 '.tex', 240 '.txt' 241 ]) 242 243 # This probably breaks on Windows. But that's probably true of 244 # everything... 245 path = urlparse.urlparse(url).path 246 basename, fileext = os.path.splitext(path) 247 189 248 if fileext: 190 249 ext = fileext 191 250 else: 192 if headers.getheader('Content-Type'): 193 mimeext = mimetypes.guess_extension(headers.gettype()) 194 if mimeext: 195 ext = mimeext 251 if mimetype: 252 extensions = mimetypes.guess_all_extensions(mimetype) 253 for extension in extensions: 254 if extension in known_ext: 255 ext = extension 256 break 196 257 else: 197 ext = '' 258 if len(extensions) > 0: 259 ext = extensions[0] 260 else: 261 ext = '' 198 262 else: 199 263 ext = '' 264 265 extmap = { 266 '.htm': '.html', 267 '.php': '.html', 268 '.PS': '.ps', 269 '.shtml': '.html', 270 '.text': '.txt', 271 } 272 # we have no real handling of no extension, .old, and .ksh 273 if ext in extmap: ext = extmap[ext] 274 if ext not in known_ext: ext = ext + '.unknown' 275 200 276 return "%04d-%s%s" % (self.group.pk, slug, ext, ) 201 277 … … 210 286 stream = urllib.urlopen(self.source_url) 211 287 return stream.getcode() 212 except :288 except IOError: 213 289 return "IOError" 214 290 else: -
asadb/groups/urls.py
r0ac15a1 r52a6940 23 23 url(r'^recent_changes/$', groups.views.GroupHistoryView.as_view(), name='manage-history', ), 24 24 url(r'^signatories/$', groups.views.view_signatories, name='signatories', ), 25 url(r'^constitutions/$', groups.views.downloaded_constitutions, name='constitutions', ), 25 26 url(r'^account_lookup/$', groups.views.account_lookup, name='account-lookup', ), 26 27 ) -
asadb/groups/views.py
r68c93e8 r51b384a 128 128 for field in self.force_required: 129 129 self.fields[field].required = True 130 self.fields['constitution_url'].help_text = mark_safe(" Please put your current constitution URL, if you have one.<br>If your constitution is currently an AFS path, you can either use the corresponding web.mit.edu (e.g., http://web.mit.edu/locker/path/to/const.html) or stuff.mit.edu path, or just use http://asa.mit.edu/const/afs/your-afs-path.<br>If you don't currently know where your constitution is, put http://mit.edu/asa/start/constitution-req.html.<br>(In either of these last two cases, we'll get in touch with you later about putting something better in.)")130 self.fields['constitution_url'].help_text = mark_safe("""Please put your current constitution URL or AFS path.<br>If you don't currently know where your constitution is, put "http://mit.edu/asa/start/constitution-req.html" and draft a constitution soon.""") 131 131 132 132 exec_only_fields = [ … … 1025 1025 1026 1026 1027 def downloaded_constitutions(request, ): 1028 constitutions = groups.models.GroupConstitution.objects 1029 constitutions = constitutions.order_by('failure_reason', 'status_msg', 'failure_date', 'group__name', ).select_related('group', 'group__group_status', ) 1030 failures = collections.defaultdict(list) 1031 successes = collections.defaultdict(list) 1032 for const in constitutions: 1033 if const.failure_reason: 1034 failures[const.failure_reason].append(const) 1035 else: 1036 successes[const.status_msg].append(const) 1037 context = {} 1038 context['failures'] = sorted(failures.items(), key=lambda x: x[0]) 1039 context['successes'] = sorted(successes.items(), key=lambda x: x[0]) 1040 context['pagename'] = 'groups' 1041 return render_to_response('groups/groups_constitutions.html', context, context_instance=RequestContext(request), ) 1042 1043 1027 1044 1028 1045 #######################
Note: See TracChangeset
for help on using the changeset viewer.