def handle(self, *args, **kwargs): try: out_dir = args[0] except IndexError: print "Requires arg: <output directory>" return data = [] qs = Profile.objects.enrolled().select_related('user') for profile in qs: docs = profile.user.documents_authored.filter(status='published') try: latest = docs.order_by('-date_written')[0] except IndexError: continue data.append((latest.date_written.strftime("%y-%m-%d"), profile)) data.sort() data.reverse() rows = [] for i, (date, profile) in enumerate(data[:250]): rows.append([str(i), str(profile.pk), profile.display_name]) env = build_envelope( profile.user.organization_set.all()[0].mailing_address, profile.full_address()) fn = os.path.join(out_dir, "%03d-%s.jpg" % (i, profile.get_blog_slug())) with open(fn, 'w') as fh: fh.write(env.getvalue()) write_csv(rows, os.path.join(out_dir, "manifest.csv"))
def print_envelopes(request): if request.GET.get("ids"): try: ids = [int(i) for i in request.GET.get("ids").split(",")] except Exception: return HttpResponse("Error parsing ids parameter") else: return HttpResponse("Try adding 'ids' parameter") profiles = Profile.objects.select_related('user').in_bulk(ids) missing = [] for pk in ids: if pk not in profiles: missing.append(pk) if missing: return HttpResponse("Can't find result for ids: %s" % missing) envelopes = [] # NOTE: inefficient -- n+1 queries. Could be improved but not worth it for # the small expected query size. for pk, profile in profiles.iteritems(): envelopes.append((utils.build_envelope( to_address=profile.full_address(), from_address=profile.user.organization_set.get().mailing_address), "%s.jpg" % profile.get_blog_slug())) zipname = "envelopes-%s" % (datetime.datetime.now().strftime("%Y-%m-%d")) # Do it all in memory for fun and profit. zip_stringio = StringIO() zip_builder = zipfile.ZipFile(zip_stringio, "w") for jpeg, name in envelopes: zip_builder.writestr("%s/%s" % (zipname, name), jpeg.getvalue()) zip_builder.close() response = HttpResponse(mimetype='application/zip') response.write(zip_stringio.getvalue()) response['Content-Disposition'] = 'attachment; filename=%s.zip' % zipname return response
def print_envelopes(request): if request.GET.get("ids"): try: ids = [int(i) for i in request.GET.get("ids").split(",")] except Exception: return HttpResponse("Error parsing ids parameter") else: return HttpResponse("Try adding 'ids' parameter") profiles = Profile.objects.select_related('user').in_bulk(ids) missing = [] for pk in ids: if pk not in profiles: missing.append(pk) if missing: return HttpResponse("Can't find result for ids: %s" % missing) envelopes = [] # NOTE: inefficient -- n+1 queries. Could be improved but not worth it for # the small expected query size. for pk, profile in profiles.iteritems(): envelopes.append((utils.build_envelope( to_address=profile.full_address(), from_address=profile.user.organization_set.get().mailing_address ), "%s.jpg" % profile.get_blog_slug())) zipname = "envelopes-%s" % (datetime.datetime.now().strftime("%Y-%m-%d")) # Do it all in memory for fun and profit. zip_stringio = StringIO() zip_builder = zipfile.ZipFile(zip_stringio, "w") for jpeg, name in envelopes: zip_builder.writestr("%s/%s" % (zipname, name), jpeg.getvalue()) zip_builder.close() response = HttpResponse(mimetype='application/zip') response.write(zip_stringio.getvalue()) response['Content-Disposition'] = 'attachment; filename=%s.zip' % zipname return response
def print_envelope(request, user_id=None, reverse=None, address=None): if user_id: user = utils.mail_filter_or_404(request.user, Profile, pk=user_id).user to_address = user.profile.full_address() else: to_address = request.GET.get("address", address) if not to_address: raise Http404 from_address = user.organization_set.get().mailing_address if reverse: from_address, to_address = to_address, from_address stringio = utils.build_envelope(to_address=to_address, from_address=from_address) response = HttpResponse(content_type="image/jpeg") response.write(stringio.getvalue()) response["Content-Disposition"] = "attachment; filename=%s-envelope.jpg" % slugify(to_address.split("\n")[0]) return response
def handle(self, *args, **kwargs): try: out_dir = args[0] except IndexError: print "Requires arg: <output directory>" return qs = Profile.objects.enrolled().annotate( count=Count('user__documents_authored')) for i, profile in enumerate(qs): env = build_envelope( profile.user.organization_set.all()[0].mailing_address, profile.full_address()) fn = os.path.join(out_dir, "%03d-%s.jpg" % (i, profile.get_blog_slug())) with open(fn, 'w') as fh: fh.write(env.getvalue())
def print_envelope(request, user_id=None, reverse=None, address=None): if user_id: user = utils.mail_filter_or_404(request.user, Profile, pk=user_id).user to_address = user.profile.full_address() else: to_address = request.GET.get('address', address) if not to_address: raise Http404 from_address = user.organization_set.get().mailing_address if reverse: from_address, to_address = to_address, from_address stringio = utils.build_envelope(to_address=to_address, from_address=from_address) response = HttpResponse(mimetype='image/jpeg') response.write(stringio.getvalue()) response['Content-Disposition'] = 'attachment; filename=%s-envelope.jpg' % \ slugify(to_address.split('\n')[0]) return response
def handle(self, *args, **kwargs): try: out_dir = args[0] except IndexError: print "Requires arg: <output directory>" return qs = Profile.objects.enrolled().annotate( count=Count('user__documents_authored') ) for i,profile in enumerate(qs): env = build_envelope( profile.user.organization_set.all()[0].mailing_address, profile.full_address() ) fn = os.path.join(out_dir, "%03d-%s.jpg" % (i, profile.get_blog_slug())) with open(fn, 'w') as fh: fh.write(env.getvalue())
def handle(self, *args, **kwargs): try: out_dir = args[0] except IndexError: print "Requires arg: <output directory>" return data = [] qs = Profile.objects.enrolled().select_related('user') for profile in qs: docs = profile.user.documents_authored.filter(status='published') try: latest = docs.order_by('-date_written')[0] except IndexError: continue data.append(( latest.date_written.strftime("%y-%m-%d"), profile )) data.sort() data.reverse() rows = [] for i,(date,profile) in enumerate(data[:250]): rows.append([ str(i), str(profile.pk), profile.display_name ]) env = build_envelope( profile.user.organization_set.all()[0].mailing_address, profile.full_address() ) fn = os.path.join(out_dir, "%03d-%s.jpg" % (i, profile.get_blog_slug())) with open(fn, 'w') as fh: fh.write(env.getvalue()) write_csv(rows, os.path.join(out_dir, "manifest.csv"))
def generate_colation(mailing): """ Generates a zip file containing all of the letters and envelopes for a particular mailing. The output has the following structure: mailings-YYYY-MM-DD/ letters/ (all letters, individually) envelopes/ (all envelopes) postcards/ (any other postcard type) all_letters.pdf -- all letters of all kinds (not postcards) combined for double-sided printing manifest.csv -- CSV file with sheet counts and names. addresses.csv -- CSV file with all addresses, one column per line, front-padded """ tmpdir = tempfile.mkdtemp(prefix="colation") outname = "mailings-%s_%s" % ( datetime.datetime.now().strftime("%Y-%m-%d"), mailing.pk, ) outdir = os.path.join(tmpdir, outname) os.makedirs(outdir) # also makes outdir manifest = {"letters": [], "postcards": []} for letter in mailing.letters.all(): if not letter.get_file(): continue details = { "recipient": letter.get_recipient_address(), "sender": letter.org.mailing_address, "type": letter.type, "file": letter.get_file(), "id": letter.id, } details["slug"] = slugify(details["recipient"].split("\n")[0]) if letter.is_postcard: manifest["postcards"].append(details) else: manifest["letters"].append(details) # Write envelopes if manifest["letters"]: envelope_dir = os.path.join(outdir, "envelopes") os.makedirs(envelope_dir) unique_envelopes = set((d["slug"], d["recipient"], d["sender"]) for d in manifest["letters"]) for slug, addr, from_address in unique_envelopes: env_fh = utils.build_envelope(from_address=from_address, to_address=addr) path = os.path.join(envelope_dir, "%s-envelope.jpg" % slug) with open(path, 'w') as fh: fh.write(env_fh.getvalue()) # Write postcards for key in ("postcards", "letters"): if not manifest[key]: continue file_dir = os.path.join(outdir, key) os.makedirs(file_dir) for details in manifest[key]: dest = os.path.join( file_dir, "{0}-{1}{2}.{3}".format( details["slug"], details["type"], details["id"], ("jpg" if key == "postcards" else "pdf"))) shutil.copy(details["file"], dest) # Replace 'file' in manifest with zipfile-relative path details["file"] = os.path.relpath(dest, outdir) # Make combined letters pdf. if manifest["letters"]: sorted_pdfs = sorted( glob.glob(os.path.join(outdir, "letters", "*.pdf"))) utils.combine_pdfs(*sorted_pdfs, add_blanks=True, filename=os.path.join(outdir, "all_letters.pdf")) # Write manifest file with open(os.path.join(outdir, "manifest.json"), 'w') as fh: json.dump(manifest, fh, indent=2) # Zip tmp_zip_path = "{0}.zip".format(outdir) zipbase = os.path.basename(outdir) proc = subprocess.Popen(["/usr/bin/zip", "-r", zipbase, zipbase], cwd=tmpdir) # zip adds ".zip" proc.communicate() # Clean up dest = os.path.join(settings.MEDIA_ROOT, "mailings", os.path.basename(outname) + ".zip") try: os.makedirs(os.path.dirname(dest)) except OSError: pass shutil.move(tmp_zip_path, dest) proc = subprocess.Popen(["rm", "-r", tmpdir]) return os.path.relpath(dest, settings.MEDIA_ROOT)
def generate_colation(mailing): """ Generates a zip file containing all of the letters and envelopes for a particular mailing. The output has the following structure: mailings-YYYY-MM-DD/ letters/ (all letters, individually) envelopes/ (all envelopes) postcards/ (any other postcard type) all_letters.pdf -- all letters of all kinds (not postcards) combined for double-sided printing manifest.csv -- CSV file with sheet counts and names. addresses.csv -- CSV file with all addresses, one column per line, front-padded """ tmpdir = tempfile.mkdtemp(prefix="colation") outname = "mailings-%s_%s" % ( datetime.datetime.now().strftime("%Y-%m-%d"), mailing.pk, ) outdir = os.path.join(tmpdir, outname) os.makedirs(outdir) # also makes outdir envelopes = set() postcards = [] letters = [] manifest = defaultdict(int) for letter in mailing.letters.all(): if not letter.get_file(): continue address = letter.get_recipient_address() slug = slugify(address.split("\n")[0]) if letter.is_postcard: postcards.append((slug, letter)) continue letters.append((slug, letter)) envelopes.add((slug, address, letter.org.mailing_address)) count = get_pdf_page_count(letter.get_file()) if count: manifest[(slug, address)] += count # Write manifest file if manifest: items = manifest.items() items.sort() rows = [(a.split("\n")[0].strip(), str((c + c % 2) / 2)) for (s, a), c in items] utils.write_csv(rows, os.path.join(outdir, "manifest.csv")) # Write envelopes if envelopes: envelope_dir = os.path.join(outdir, "envelopes") os.makedirs(envelope_dir) for slug, addr, from_address in envelopes: env_fh = utils.build_envelope(from_address=from_address, to_address=addr) path = os.path.join(envelope_dir, "%s-envelope.jpg" % slug) with open(path, 'w') as fh: fh.write(env_fh.getvalue()) # Write addresses CSV sorted_addresses = [a for s, a, r in sorted(envelopes)] utils.write_address_csv(sorted_addresses, os.path.join(outdir, "addresses.csv")) # Write postcards if postcards: postcard_dir = os.path.join(outdir, "postcards") os.makedirs(postcard_dir) for slug, postcard in postcards: dest = os.path.join( postcard_dir, "{0}-{1}{2}.jpg".format(slug, postcard.type, postcard.pk)) shutil.copy(postcard.get_file(), dest) # Copy and combine letters if letters: letter_dir = os.path.join(outdir, "letters") os.makedirs(letter_dir) for slug, letter in letters: dest = os.path.join( letter_dir, "{0}-{1}{2}.pdf".format(slug, letter.type, letter.pk)) shutil.copy(letter.get_file(), dest) sorted_pdfs = sorted(glob.glob(os.path.join(letter_dir, "*.pdf"))) utils.combine_pdfs(*sorted_pdfs, add_blanks=True, filename=os.path.join(outdir, "all_letters.pdf")) # Zip tmp_zip_path = "{0}.zip".format(outdir) zipbase = os.path.basename(outdir) proc = subprocess.Popen(["/usr/bin/zip", "-r", zipbase, zipbase], cwd=tmpdir) # zip adds ".zip" proc.communicate() # Clean up dest = os.path.join(settings.MEDIA_ROOT, "mailings", os.path.basename(outname) + ".zip") try: os.makedirs(os.path.dirname(dest)) except OSError: pass shutil.move(tmp_zip_path, dest) proc = subprocess.Popen(["rm", "-r", tmpdir]) return os.path.relpath(dest, settings.MEDIA_ROOT)
def generate_colation(mailing): """ Generates a zip file containing all of the letters and envelopes for a particular mailing. The output has the following structure: mailings-YYYY-MM-DD/ letters/ (all letters, individually) envelopes/ (all envelopes) postcards/ (any other postcard type) all_letters.pdf -- all letters of all kinds (not postcards) combined for double-sided printing manifest.csv -- CSV file with sheet counts and names. addresses.csv -- CSV file with all addresses, one column per line, front-padded """ tmpdir = tempfile.mkdtemp(prefix="colation") outname = "mailings-%s_%s" % ( datetime.datetime.now().strftime("%Y-%m-%d"), mailing.pk, ) outdir = os.path.join(tmpdir, outname) os.makedirs(outdir) # also makes outdir envelopes = set() postcards = [] letters = [] manifest = defaultdict(int) for letter in mailing.letters.all(): if not letter.get_file(): continue address = letter.get_recipient_address() slug = slugify(address.split("\n")[0]) if letter.is_postcard: postcards.append((slug, letter)) continue letters.append((slug, letter)) envelopes.add((slug, address, letter.org.mailing_address)) count = get_pdf_page_count(letter.get_file()) if count: manifest[(slug, address)] += count # Write manifest file if manifest: items = manifest.items() items.sort() rows = [(a.split("\n")[0].strip(), str((c + c%2)/2)) for (s, a),c in items] utils.write_csv(rows, os.path.join(outdir, "manifest.csv")) # Write envelopes if envelopes: envelope_dir = os.path.join(outdir, "envelopes") os.makedirs(envelope_dir) for slug, addr, from_address in envelopes: env_fh = utils.build_envelope( from_address=from_address, to_address=addr) path = os.path.join(envelope_dir, "%s-envelope.jpg" % slug) with open(path, 'w') as fh: fh.write(env_fh.getvalue()) # Write addresses CSV sorted_addresses = [a for s, a, r in sorted(envelopes)] utils.write_address_csv(sorted_addresses, os.path.join(outdir, "addresses.csv")) # Write postcards if postcards: postcard_dir = os.path.join(outdir, "postcards") os.makedirs(postcard_dir) for slug, postcard in postcards: dest = os.path.join(postcard_dir, "{0}-{1}{2}.jpg".format( slug, postcard.type, postcard.pk )) shutil.copy(postcard.get_file(), dest) # Copy and combine letters if letters: letter_dir = os.path.join(outdir, "letters") os.makedirs(letter_dir) for slug, letter in letters: dest = os.path.join(letter_dir, "{0}-{1}{2}.pdf".format(slug, letter.type, letter.pk)) shutil.copy(letter.get_file(), dest) sorted_pdfs = sorted(glob.glob(os.path.join(letter_dir, "*.pdf"))) utils.combine_pdfs(*sorted_pdfs, add_blanks=True, filename=os.path.join(outdir, "all_letters.pdf") ) # Zip tmp_zip_path = "{0}.zip".format(outdir) zipbase = os.path.basename(outdir) proc = subprocess.Popen(["/usr/bin/zip", "-r", zipbase, zipbase], cwd=tmpdir) # zip adds ".zip" proc.communicate() # Clean up dest = os.path.join(settings.MEDIA_ROOT, "mailings", os.path.basename(outname) + ".zip") try: os.makedirs(os.path.dirname(dest)) except OSError: pass shutil.move(tmp_zip_path, dest) proc = subprocess.Popen(["rm", "-r", tmpdir]) return os.path.relpath(dest, settings.MEDIA_ROOT)
def generate_colation(mailing): """ Generates a zip file containing all of the letters and envelopes for a particular mailing. The output has the following structure: mailings-YYYY-MM-DD/ letters/ (all letters, individually) envelopes/ (all envelopes) postcards/ (any other postcard type) all_letters.pdf -- all letters of all kinds (not postcards) combined for double-sided printing manifest.csv -- CSV file with sheet counts and names. addresses.csv -- CSV file with all addresses, one column per line, front-padded """ tmpdir = tempfile.mkdtemp(prefix="colation") outname = "mailings-%s_%s" % ( datetime.datetime.now().strftime("%Y-%m-%d"), mailing.pk, ) outdir = os.path.join(tmpdir, outname) os.makedirs(outdir) # also makes outdir manifest = {"letters": [], "postcards": []} for letter in mailing.letters.all(): if not letter.get_file(): continue details = { "recipient": letter.get_recipient_address(), "sender": letter.org.mailing_address, "type": letter.type, "file": letter.get_file(), "id": letter.id, } details["slug"] = slugify(details["recipient"].split("\n")[0]) if letter.is_postcard: manifest["postcards"].append(details) else: manifest["letters"].append(details) # Write envelopes if manifest["letters"]: envelope_dir = os.path.join(outdir, "envelopes") os.makedirs(envelope_dir) unique_envelopes = set( (d["slug"], d["recipient"], d["sender"]) for d in manifest["letters"] ) for slug, addr, from_address in unique_envelopes: env_fh = utils.build_envelope(from_address=from_address, to_address=addr) path = os.path.join(envelope_dir, "%s-envelope.jpg" % slug) with open(path, 'w') as fh: fh.write(env_fh.getvalue()) # Write postcards for key in ("postcards", "letters"): if not manifest[key]: continue file_dir = os.path.join(outdir, key) os.makedirs(file_dir) for details in manifest[key]: dest = os.path.join(file_dir, "{0}-{1}{2}.{3}".format( details["slug"], details["type"], details["id"], ("jpg" if key == "postcards" else "pdf") )) shutil.copy(details["file"], dest) # Replace 'file' in manifest with zipfile-relative path details["file"] = os.path.relpath(dest, outdir) # Make combined letters pdf. if manifest["letters"]: sorted_pdfs = sorted(glob.glob(os.path.join(outdir, "letters", "*.pdf"))) utils.combine_pdfs(*sorted_pdfs, add_blanks=True, filename=os.path.join(outdir, "all_letters.pdf") ) # Write manifest file with open(os.path.join(outdir, "manifest.json"), 'w') as fh: json.dump(manifest, fh, indent=2) # Zip tmp_zip_path = "{0}.zip".format(outdir) zipbase = os.path.basename(outdir) proc = subprocess.Popen(["/usr/bin/zip", "-r", zipbase, zipbase], cwd=tmpdir) # zip adds ".zip" proc.communicate() # Clean up dest = os.path.join(settings.MEDIA_ROOT, "mailings", os.path.basename(outname) + ".zip") try: os.makedirs(os.path.dirname(dest)) except OSError: pass shutil.move(tmp_zip_path, dest) proc = subprocess.Popen(["rm", "-r", tmpdir]) return os.path.relpath(dest, settings.MEDIA_ROOT)