Changeset e0632f6 for asadb/groups


Ignore:
Timestamp:
Sep 10, 2012, 5:02:55 AM (13 years ago)
Author:
Alex Dehnert <adehnert@…>
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)
Message:

Merge branch 'constitutions'

Location:
asadb/groups
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • asadb/groups/gather_constitutions.py

    rfb1c047 rc632b1c  
    1212import datetime
    1313import subprocess
     14
     15import django.contrib.auth.models
     16import reversion
    1417
    1518import groups.models
     
    7174        print "%4d\t%s" % (len(gs), code, )
    7275
     76def list_constitutions():
     77    constitutions = groups.models.GroupConstitution.objects.all()
     78    for const in constitutions:
     79        if const.dest_file: print const.dest_file
     80
    7381if __name__ == '__main__':
    7482    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
    7689        update_repo(additions, changed)
    7790    elif sys.argv[1] == "webstat":
    7891        webstat()
     92    elif sys.argv[1] == "list":
     93        list_constitutions()
    7994    else:
    8095        raise NotImplementedError
  • asadb/groups/models.py

    r3af5d74 re0632f6  
    1111import re
    1212import shutil
     13import urlparse
    1314import urllib
     15import urllib2
    1416
    1517import settings
     18
     19import mit
    1620
    1721# Create your models here.
     
    3438    group_funding = models.ForeignKey('GroupFunding', null=True, blank=True, db_index=True, )
    3539    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])
    3741    meeting_times = models.TextField(blank=True)
    3842    advisor_name = models.CharField(max_length=100, blank=True)
     
    137141    failure_reason = models.CharField(max_length=100, blank=True, default="")
    138142
     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
    139161    def update(self, ):
    140162        url = self.source_url
     
    142164        old_success = (self.failure_date is None)
    143165        if url:
    144             url_opener = urllib.FancyURLopener()
    145             now = datetime.datetime.now()
     166            # Fetch the file
     167            error_msg = None
    146168            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)
    148183            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"
    170188                else:
    171                     # changed
    172                     mover(tmp_path, dest_path)
    173                     self.last_update = now
    174                     self.status_msg = "updated in place"
    175             self.last_download = now
    176             self.failure_date = None
    177             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
    179197            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
    180225        else:
     226            self.record_failure("no url")
    181227            success = False
    182             self.status_msg = "no url"
    183             self.failure_reason = self.status_msg
     228
    184229        return (success, self.status_msg, old_success, )
    185230
    186     def compute_filename(self, tmp_path, headers, ):
     231    def compute_filename(self, url, mimetype):
    187232        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
    189248        if fileext:
    190249            ext = fileext
    191250        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
    196257                else:
    197                     ext = ''
     258                    if len(extensions) > 0:
     259                        ext = extensions[0]
     260                    else:
     261                        ext = ''
    198262            else:
    199263                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
    200276        return "%04d-%s%s" % (self.group.pk, slug, ext, )
    201277
     
    210286                stream = urllib.urlopen(self.source_url)
    211287                return stream.getcode()
    212             except:
     288            except IOError:
    213289                return "IOError"
    214290        else:
  • asadb/groups/urls.py

    r0ac15a1 r52a6940  
    2323    url(r'^recent_changes/$', groups.views.GroupHistoryView.as_view(), name='manage-history', ),
    2424    url(r'^signatories/$', groups.views.view_signatories, name='signatories', ),
     25    url(r'^constitutions/$', groups.views.downloaded_constitutions, name='constitutions', ),
    2526    url(r'^account_lookup/$', groups.views.account_lookup, name='account-lookup', ),
    2627)
  • asadb/groups/views.py

    r68c93e8 r51b384a  
    128128        for field in self.force_required:
    129129            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.""")
    131131
    132132    exec_only_fields = [
     
    10251025
    10261026
     1027def 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
    10271044
    10281045#######################
Note: See TracChangeset for help on using the changeset viewer.