diff --git a/symposion/proposals/actions.py b/symposion/proposals/actions.py index eeeb6289..f5dfd19f 100644 --- a/symposion/proposals/actions.py +++ b/symposion/proposals/actions.py @@ -25,13 +25,13 @@ def export_as_csv_action(description=None, fields=None, exclude=None, excludeset = set(exclude) field_names = field_names - excludeset response = HttpResponse(content_type="text/csv") - response["Content-Disposition"] = "attachment; filename=%s.csv" % unicode(opts).replace(".", "_") + response["Content-Disposition"] = "attachment; filename=%s.csv" % str(opts).replace(".", "_") writer = csv.writer(response) if header: writer.writerow(list(field_names)) for obj in queryset: writer.writerow( - [unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) + [str(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) return response if description is None: description = _("Export selected objects as CSV file") diff --git a/symposion/proposals/models.py b/symposion/proposals/models.py index e4b9e563..bdf43ffd 100644 --- a/symposion/proposals/models.py +++ b/symposion/proposals/models.py @@ -205,6 +205,7 @@ class ProposalBase(models.Model): def __str__(self): return self.title + reversion.register(ProposalBase) diff --git a/symposion/reviews/admin.py b/symposion/reviews/admin.py index c5b0dd48..5144c2ca 100644 --- a/symposion/reviews/admin.py +++ b/symposion/reviews/admin.py @@ -17,4 +17,4 @@ admin.site.register( list_display=['proposal', 'status', 'score', 'vote_count', 'accepted'] ) -admin.site.register(ResultNotification) \ No newline at end of file +admin.site.register(ResultNotification) diff --git a/symposion/reviews/management/commands/assign_reviewers.py b/symposion/reviews/management/commands/assign_reviewers.py index 20594f4c..6364e0fc 100644 --- a/symposion/reviews/management/commands/assign_reviewers.py +++ b/symposion/reviews/management/commands/assign_reviewers.py @@ -8,5 +8,5 @@ class Command(BaseCommand): def handle(self, *args, **options): for proposal in ProposalBase.objects.filter(cancelled=0): - print "Creating assignments for %s" % (proposal.title,) + print("Creating assignments for %s" % proposal.title) ReviewAssignment.create_assignments(proposal) diff --git a/symposion/reviews/management/commands/create_review_permissions.py b/symposion/reviews/management/commands/create_review_permissions.py index 67dfc96b..2f21754a 100644 --- a/symposion/reviews/management/commands/create_review_permissions.py +++ b/symposion/reviews/management/commands/create_review_permissions.py @@ -22,4 +22,4 @@ class Command(BaseCommand): content_type__pk=ct.id, defaults={"name": "Can %s %s" % (action, ps), "content_type": ct} ) - print perm + print(perm) diff --git a/symposion/reviews/models.py b/symposion/reviews/models.py index d47feff5..63c190cf 100644 --- a/symposion/reviews/models.py +++ b/symposion/reviews/models.py @@ -47,6 +47,8 @@ class Votes(object): (MINUS_TWO, _("−2 — Serious issues and I will argue to reject this proposal.")), (ABSTAIN, _("Abstain - I do not want to review this proposal and I do not want to see it again.")), ] + + VOTES = Votes() @@ -395,4 +397,6 @@ def accepted_proposal(sender, instance=None, **kwargs): promote_proposal(instance.proposal) else: unpromote_proposal(instance.proposal) + + post_save.connect(accepted_proposal, sender=ProposalResult) diff --git a/symposion/reviews/views.py b/symposion/reviews/views.py index 3768225d..c45dbf4a 100644 --- a/symposion/reviews/views.py +++ b/symposion/reviews/views.py @@ -78,23 +78,23 @@ REVIEW_STATUS_FILTERS = { # proposals with at least VOTE_THRESHOLD reviews and at least one +2 and no -2s, sorted by # the 'score' POSITIVE: lambda qs: qs.filter(result__vote_count__gte=VOTE_THRESHOLD, result__plus_two__gt=0, - result__minus_two=0).order_by("-result__score"), + result__minus_two=0).order_by("-result__score"), # proposals with at least VOTE_THRESHOLD reviews and at least one -2 and no +2s, reverse # sorted by the 'score' NEGATIVE: lambda qs: qs.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_two__gt=0, - result__plus_two=0).order_by("result__score"), + result__plus_two=0).order_by("result__score"), # proposals with at least VOTE_THRESHOLD reviews and neither a +2 or a -2, sorted by total # votes (lowest first) INDIFFERENT: lambda qs: qs.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_two=0, - result__plus_two=0).order_by("result__vote_count"), + result__plus_two=0).order_by("result__vote_count"), # proposals with at least VOTE_THRESHOLD reviews and both a +2 and -2, sorted by total # votes (highest first) - CONTROVERSIAL: lambda qs: qs.filter(result__vote_count__gte=VOTE_THRESHOLD, - result__plus_two__gt=0, result__minus_two__gt=0) - .order_by("-result__vote_count"), + CONTROVERSIAL: lambda qs: qs.filter( + result__vote_count__gte=VOTE_THRESHOLD, result__plus_two__gt=0, + result__minus_two__gt=0).order_by("-result__vote_count"), # proposals with fewer than VOTE_THRESHOLD reviews - TOO_FEW: lambda qs: qs.filter(result__vote_count__lt=VOTE_THRESHOLD) - .order_by("result__vote_count"), + TOO_FEW: lambda qs: qs.filter( + result__vote_count__lt=VOTE_THRESHOLD).order_by("result__vote_count"), } @@ -153,7 +153,7 @@ def review_all_proposals_csv(request): # The fields from each proposal object to report in the csv fields = [ - "id", "proposal_type", "speaker_name","speaker_email", "title", + "id", "proposal_type", "speaker_name", "speaker_email", "title", "submitted", "other_speakers", "speaker_travel", "speaker_accommodation", "cancelled", "status", "score", "total_votes", "minus_two", "minus_one", "plus_one", "plus_two", @@ -189,11 +189,6 @@ def review_all_proposals_csv(request): csv_line = [getattr(proposal, field) for field in fields] - # Enusre that unicode items are handled properly. - for i, item in enumerate(csv_line): - if isinstance(item, unicode): - csv_line[i] = item.encode("utf8") - writer.writerow(csv_line) return response @@ -229,7 +224,7 @@ def review_random_proposal(request, section_slug): # Select a proposal with less than the median number of total votes proposals = proposals_generator(request, queryset, check_speaker=False) proposals = list(proposals) - proposals.sort(key = lambda proposal: proposal.total_votes) + proposals.sort(key=lambda proposal: proposal.total_votes) # The first half is the median or less. # The +1 means we round _up_. proposals = proposals[:(len(proposals) + 1) / 2] @@ -319,7 +314,7 @@ def review_admin(request, section_slug): yield user reviewers_sorted = list(reviewers()) - reviewers_sorted.sort(key= lambda reviewer: 0 - reviewer.total_votes) + reviewers_sorted.sort(key=lambda reviewer: 0 - reviewer.total_votes) ctx = { "section_slug": section_slug, diff --git a/symposion/schedule/helpers.py b/symposion/schedule/helpers.py index 68e72e39..2802f489 100644 --- a/symposion/schedule/helpers.py +++ b/symposion/schedule/helpers.py @@ -28,4 +28,4 @@ def create_slot(section_slug, date, kind, start, end, rooms): slot_room.slot = slot slot_room.room = room slot_room.save(force_insert=True) - print "created {} [start={}; end={}]".format(slot.kind.label, slot.start, slot.end) + print("created {} [start={}; end={}]".format(slot.kind.label, slot.start, slot.end)) diff --git a/symposion/schedule/views.py b/symposion/schedule/views.py index 6e85a2fd..f7375523 100644 --- a/symposion/schedule/views.py +++ b/symposion/schedule/views.py @@ -21,6 +21,7 @@ from symposion.schedule.models import Schedule, Day, Slot, Presentation, Session from symposion.schedule.timetable import TimeTable from symposion.conference.models import Conference + def fetch_schedule(slug): qs = Schedule.objects.all() @@ -265,11 +266,13 @@ def schedule_json(request): content_type="application/json" ) + class EventFeed(ICalFeed): product_id = '-//linux.conf.au/schedule//EN' timezone = settings.TIME_ZONE filename = 'conference.ics' + def description(self): return Conference.objects.all().first().title @@ -283,7 +286,7 @@ class EventFeed(ICalFeed): def item_title(self, item): if hasattr(item.content, 'proposal'): - title = item.content.title + title = item.content.title else: title = item.kind if item.kind else "Slot" return title @@ -305,18 +308,18 @@ class EventFeed(ICalFeed): def item_location(self, item): return ", ".join(room["name"] for room in item.rooms.values()) - def item_link(self, item): + def item_link(self, item) -> str: if hasattr(item.content, 'proposal'): - return 'http://%s%s' % ( - Site.objects.get_current().domain, - reverse('schedule_presentation_detail', args=[item.content.pk]) - ) + return ( + 'http://%s%s' % (Site.objects.get_current().domain, + reverse('schedule_presentation_detail', args=[item.content.pk]))) else: return 'http://%s' % Site.objects.get_current().domain - + def item_guid(self, item): return '%d@%s' % (item.pk, Site.objects.get_current().domain) + def session_list(request): sessions = Session.objects.all().order_by('pk') diff --git a/symposion/speakers/management/commands/export_speaker_data.py b/symposion/speakers/management/commands/export_speaker_data.py index 00e82588..08da5891 100644 --- a/symposion/speakers/management/commands/export_speaker_data.py +++ b/symposion/speakers/management/commands/export_speaker_data.py @@ -9,11 +9,12 @@ from symposion.speakers.models import Speaker class Command(BaseCommand): def handle(self, *args, **options): - csv_file = csv.writer(open(os.path.join(os.getcwd(), "speakers.csv"), "wb")) - csv_file.writerow(["Name", "Bio"]) + with open(os.path.join(os.getcwd(), "speakers.csv"), "w") as csv_file: + csv_writer = csv.writer(csv_file) + csv_writer.writerow(["Name", "Bio"]) - for speaker in Speaker.objects.all(): - csv_file.writerow([ - speaker.name.encode("utf-8"), - speaker.biography.encode("utf-8"), - ]) + for speaker in Speaker.objects.all(): + csv_writer.writerow([ + speaker.name, + speaker.biography, + ]) diff --git a/symposion/speakers/models.py b/symposion/speakers/models.py index ddbbceee..98d0d8a8 100644 --- a/symposion/speakers/models.py +++ b/symposion/speakers/models.py @@ -66,9 +66,9 @@ class Speaker(models.Model): accessibility = models.TextField( blank=True, help_text=_("Please describe any special accessibility requirements " - "that you may have. Edit using " - "Markdown."), + "that you may have. Edit using " + "Markdown."), verbose_name=_("Accessibility requirements")) accessibility_html = models.TextField(blank=True) travel_assistance = models.BooleanField( diff --git a/symposion/sponsorship/management/commands/export_sponsors_data.py b/symposion/sponsorship/management/commands/export_sponsors_data.py index 61172d44..a20e3f3b 100644 --- a/symposion/sponsorship/management/commands/export_sponsors_data.py +++ b/symposion/sponsorship/management/commands/export_sponsors_data.py @@ -30,48 +30,48 @@ class Command(BaseCommand): except: pass - csv_file = csv.writer( - open(os.path.join(os.getcwd(), "build", "sponsors.csv"), "wb") - ) - csv_file.writerow(["Name", "URL", "Level", "Description"]) + with open(os.path.join(os.getcwd(), "build", "sponsors.csv"), "w") as csv_file: + csv_writer = csv.writer(csv_file) + csv_writer.writerow(["Name", "URL", "Level", "Description"]) - for sponsor in Sponsor.objects.all(): - path = os.path.join(os.getcwd(), "build", slugify(sponsor.name)) - try: - os.makedirs(path) - except: - pass + for sponsor in Sponsor.objects.all(): + path = os.path.join(os.getcwd(), "build", slugify(sponsor.name)) + try: + os.makedirs(path) + except: + pass - data = { - "name": sponsor.name, - "url": sponsor.external_url, - "level": sponsor.level.name, - "description": "", - } - for sponsor_benefit in sponsor.sponsor_benefits.all(): - if sponsor_benefit.benefit_id == 2: - data["description"] = sponsor_benefit.text - if sponsor_benefit.benefit_id == 1: - if sponsor_benefit.upload: - data["ad"] = sponsor_benefit.upload.path - if sponsor_benefit.benefit_id == 7: - if sponsor_benefit.upload: - data["logo"] = sponsor_benefit.upload.path + data = { + "name": sponsor.name, + "url": sponsor.external_url, + "level": sponsor.level.name, + "description": "", + } - if "ad" in data: - ad_path = data.pop("ad") - shutil.copy(ad_path, path) - if "logo" in data: - logo_path = data.pop("logo") - shutil.copy(logo_path, path) + for sponsor_benefit in sponsor.sponsor_benefits.all(): + if sponsor_benefit.benefit_id == 2: + data["description"] = sponsor_benefit.text + if sponsor_benefit.benefit_id == 1: + if sponsor_benefit.upload: + data["ad"] = sponsor_benefit.upload.path + if sponsor_benefit.benefit_id == 7: + if sponsor_benefit.upload: + data["logo"] = sponsor_benefit.upload.path - csv_file.writerow([ - data["name"].encode("utf-8"), - data["url"].encode("utf-8"), - data["level"].encode("utf-8"), - data["description"].encode("utf-8") - ]) + if "ad" in data: + ad_path = data.pop("ad") + shutil.copy(ad_path, path) + if "logo" in data: + logo_path = data.pop("logo") + shutil.copy(logo_path, path) - zipdir( - os.path.join(os.getcwd(), "build"), - os.path.join(os.getcwd(), "sponsors.zip")) + csv_writer.writerow([ + data["name"], + data["url"], + data["level"], + data["description"] + ]) + + zipdir( + os.path.join(os.getcwd(), "build"), + os.path.join(os.getcwd(), "sponsors.zip")) diff --git a/symposion/sponsorship/management/commands/reset_sponsor_benefits.py b/symposion/sponsorship/management/commands/reset_sponsor_benefits.py index 3c17efab..efc7edba 100644 --- a/symposion/sponsorship/management/commands/reset_sponsor_benefits.py +++ b/symposion/sponsorship/management/commands/reset_sponsor_benefits.py @@ -19,7 +19,7 @@ class Command(BaseCommand): sponsor=sponsor, benefit=benefit_level.benefit) if created: - print "created", sponsor_benefit, "for", sponsor + print("created %s for %s" % (sponsor_benefit, sponsor)) # and set to default limits for this level. sponsor_benefit.max_words = benefit_level.max_words diff --git a/symposion/sponsorship/models.py b/symposion/sponsorship/models.py index f28bc57e..f93bf8c2 100644 --- a/symposion/sponsorship/models.py +++ b/symposion/sponsorship/models.py @@ -203,12 +203,16 @@ class Sponsor(models.Model): def _store_initial_level(sender, instance, **kwargs): if instance: instance._initial_level_id = instance.level_id + + post_init.connect(_store_initial_level, sender=Sponsor) def _check_level_change(sender, instance, created, **kwargs): if instance and (created or instance.level_id != instance._initial_level_id): instance.reset_benefits() + + post_save.connect(_check_level_change, sender=Sponsor) @@ -330,4 +334,6 @@ def _denorm_weblogo(sender, instance, created, **kwargs): sponsor = instance.sponsor sponsor.sponsor_logo = instance sponsor.save() + + post_save.connect(_denorm_weblogo, sender=SponsorBenefit) diff --git a/symposion/teams/admin.py b/symposion/teams/admin.py index 1a27c7ee..a8c3bec7 100644 --- a/symposion/teams/admin.py +++ b/symposion/teams/admin.py @@ -13,4 +13,5 @@ class MembershipAdmin(VersionAdmin): list_filter = ["team"] search_fields = ["user__username"] + admin.site.register(Membership, MembershipAdmin) diff --git a/symposion/teams/backends.py b/symposion/teams/backends.py index 0effdc2d..a882bf5d 100644 --- a/symposion/teams/backends.py +++ b/symposion/teams/backends.py @@ -16,16 +16,16 @@ class TeamPermissionsBackend(object): if user_obj.is_anonymous() or obj is not None: return set() if not hasattr(user_obj, "_team_perm_cache"): - # Member permissions + # Member permissions memberships = Team.objects.filter( - Q(memberships__user=user_obj), + Q(memberships__user=user_obj), Q(memberships__state="member"), ) perms = memberships.values_list( "permissions__content_type__app_label", "permissions__codename" ).order_by() - permissions = ["%s.%s" % (ct, name) for ct, name in perms] + permissions = ["%s.%s" % (ct, name) for ct, name in perms] # Manager permissions memberships = Team.objects.filter( Q(memberships__user=user_obj), @@ -35,7 +35,7 @@ class TeamPermissionsBackend(object): "manager_permissions__content_type__app_label", "manager_permissions__codename" ).order_by() - permissions += ["%s.%s" % (ct, name) for ct, name in perms] + permissions += ["%s.%s" % (ct, name) for ct, name in perms] user_obj._team_perm_cache = set(permissions) return user_obj._team_perm_cache diff --git a/symposion/teams/models.py b/symposion/teams/models.py index 774dfbd8..f6ab7253 100644 --- a/symposion/teams/models.py +++ b/symposion/teams/models.py @@ -69,6 +69,7 @@ class Team(models.Model): verbose_name = _('Team') verbose_name_plural = _('Teams') + MEMBERSHIP_STATE_CHOICES = [ ("applied", _("applied")), ("invited", _("invited")), @@ -93,4 +94,5 @@ class Membership(models.Model): verbose_name = _("Membership") verbose_name_plural = _("Memberships") + reversion.register(Membership) diff --git a/symposion/utils/mail.py b/symposion/utils/mail.py index ed90eeb1..91e37891 100644 --- a/symposion/utils/mail.py +++ b/symposion/utils/mail.py @@ -53,16 +53,6 @@ def __send_email__(template_prefix, to, kind, **kwargs): from_email = settings.DEFAULT_FROM_EMAIL - try: - bcc_email = settings.ENVELOPE_BCC_LIST - except AttributeError: - bcc_email = None - - try: - bcc_email = settings.ENVELOPE_BCC_LIST - except AttributeError: - bcc_email = None - email = EmailMultiAlternatives(subject, message_plaintext, from_email, to) email.attach_alternative(message_html, "text/html") email.send()