Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ntrrgc committed Jan 13, 2013
0 parents commit 5a16ec1
Show file tree
Hide file tree
Showing 21 changed files with 337 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.swp
*.pyc
static/lasana/css
uploads/*
dbfile
7 changes: 7 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright (c) 2012 ntrrgc

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Lasaña, a temporary file hosting service
========================================

This is a WIP, but feel free to dig in source.
Empty file added __init__.py
Empty file.
7 changes: 7 additions & 0 deletions admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin
from . models import Meal

class MealAdmin(admin.ModelAdmin):
pass

admin.site.register(Meal, MealAdmin)
14 changes: 14 additions & 0 deletions forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.forms import Form, FileField, IntegerField, ChoiceField

from . models import Meal

class MealCreateForm(Form):
file = FileField()
expires_in = ChoiceField(choices=(
(1, "1 minute"),
(30, "30 minutes"),
(60, "1 hour"),
(180, "3 hours"),
(60*24, "1 day"),
(60*24*7, "1 week"),
), initial=30)
Empty file added management/__init__.py
Empty file.
Empty file added management/commands/__init__.py
Empty file.
Empty file added management/commands/_private.py
Empty file.
18 changes: 18 additions & 0 deletions management/commands/deletemeal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.core.management.base import BaseCommand, CommandError

from lasana.models import Meal

class Command(BaseCommand):
args = '<meal_id meal_id>'
help = 'Deletes the meal with the specified id'

def handle(self, *args, **options):
for meal_id in args:
try:
meal = Meal.objects.get(id=int(meal_id))
except Meal.DoesNotExist:
raise CommandError('Meal "%s" does not exist' % meal_id)

meal.delete()

self.stdout.write('Successfully deleted meal "%s"\n' % meal_id)
22 changes: 22 additions & 0 deletions management/commands/wash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.core.management.base import BaseCommand, CommandError

from lasana.models import Meal

from django.utils import timezone

class Command(BaseCommand):
args = ''
help = 'Deletes expired meals'

def handle(self, *args, **options):
now = timezone.now()
old_meals = Meal.objects.all().order_by("expiration_time")

for meal in old_meals:
if meal.is_expired(now):
meal_id = meal.id

meal.delete()
self.stdout.write('Thrown away expired meal "%d"\n' % meal_id)
else:
break
40 changes: 40 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from django.db.models import Model, CharField, FileField, DateTimeField

from django.conf import settings

from django.utils import timezone

import string
import random

class Meal(Model):
id_length = 4
id = CharField(max_length=id_length, db_index=True, primary_key=True)
file = FileField(upload_to=settings.LASANA_UPLOAD_ROOT)
expiration_time = DateTimeField(db_index=True)

def generate_auto_id(self):
#Theoretically, we can have up to 46656 meals, but having 10k would be enough to worry
if Meal.objects.count() > 10000:
raise "Too much meals"

while True:
random_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(4))
if len(Meal.objects.filter(id=random_string)) == 0:
self.id = random_string
return self.id

def is_expired(self, now=None):
if not now:
now = timezone.now()
return now > self.expiration_time

class Meta:
ordering = ['expiration_time']

def __unicode__(self):
now = timezone.now()
if now > self.expiration_time:
return "%s, expired for %s" % (self.file.url, now - self.expiration_time)
else:
return "%s, expires in %s" % (self.file.url, self.expiration_time - now)
24 changes: 24 additions & 0 deletions sendfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.http import HttpResponse, Http404
from django.conf import settings
import os

from django.conf import settings

#For no-XSendfile approach
from django.core.servers.basehttp import FileWrapper

def send(request, file):
if not file:
raise Http404

if settings.LASANA_USE_X_SENDFILE:
response = HttpResponse()
response['Content-Disposition'] = 'filename=%s' % os.path.basename(file.name)
response['X-Sendfile'] = file.path
return response
else:
response = HttpResponse(FileWrapper(file))
response['Content-Disposition'] = 'filename=%s' % os.path.basename(file.name)
del response['content-type'] #let the web server guess
response['Content-Length'] = file.size
return response
64 changes: 64 additions & 0 deletions static/lasana/sass/stylesheet.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
@import url(http://fonts.googleapis.com/css?family=Donegal+One)

$body_font: 'Donegal One', serif
$content_width: 600px
$content_border_color: #ff912f

body
background: #fff8da
font-family: $body_font
font-size: 18px

h1, #miau
text-align: center

#content
border: 5px dotted $content_border_color
width: $content_width
margin-left: auto
margin-right: auto
padding: 30px

form
width: 100%
display: table
border-collapse: separate
border-spacing: 2px
border-top: 1px solid lightgray
border-left: 1px solid lightgray
border-right: 1px solid black
border-bottom: 1px solid black

form > .field
display: table-row

form > .field > .cell
display: table-cell
border-top: 1px solid black
border-left: 1px solid black
border-right: 1px solid lightgray
border-bottom: 1px solid lightgray
padding: 10px 10px
text-align: left

#lasagna_url_field
box-sizing: border-box
width: 100%
border: 1px solid $content_border_color
padding: 3px
font-family: $body_font
font-size: 36px

#copyright_footer
padding-top: 50px
width: $content_width
margin: 0 auto

hr
width: $content_width
border: 0
border-top: 2px solid $content_border_color

#copyright_footer_note
font-size: 70%
text-align: center
21 changes: 21 additions & 0 deletions templates/lasana/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% load staticfiles %}<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Lasaña{% endblock %}</title>
<link rel="stylesheet" href="{% static 'lasana/css/stylesheet.css' %}" />
</head>
<body>
<h1>Lasaña</h1>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="copyright_footer">
<hr/>
<div id="copyright_footer_note">
{% include "lasana/copyright_footer_note.html" %}
</div>
</div>
</body>
</html>
4 changes: 4 additions & 0 deletions templates/lasana/copyright_footer_note.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
&copy; John Titor 2036
<span style="color: #737373">
Redefine <em>'templates/lasana/copyright_footer_note.html'</em> to edit this note.
</span>
11 changes: 11 additions & 0 deletions templates/lasana/meal_create_success.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends "lasana/base.html" %}

{% block content %}
<p>Share this lasagna:</p>
<input id="lasagna_url_field" type="text" readonly value="{{ meal_serve_absolute_url }}"/>
<script>
<!-- Select URL -->
document.getElementById("lasagna_url_field").select()
</script>
<p><a href="{% url meal-create %}">Store more</a></p>
{% endblock %}
14 changes: 14 additions & 0 deletions templates/lasana/meal_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends "lasana/base.html" %}

{% block content %}
<form enctype="multipart/form-data" action="" method="POST">
{% for field in form %}
<div class="field">
<div class="cell">{{ field.label_tag }}</div>
<div class="cell">{{ field }}{{ field.errors }}</div>
</div>
{% endfor %}
{% csrf_token %}
<input type="submit" value="Put in the fridge"/>
</form>
{% endblock %}
16 changes: 16 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""

from django.test import TestCase


class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
8 changes: 8 additions & 0 deletions urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.conf.urls import patterns, include, url

from . import views

urlpatterns = patterns('',
url(r'^$', views.MealCreateView.as_view(), name='meal-create'),
url(r'^(?P<meal_id>[A-Z0-9]+)/$', views.MealServeView.as_view(), name='meal-serve'),
)
58 changes: 58 additions & 0 deletions views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.views.generic.edit import CreateView, FormView
from django.views.generic.base import View, TemplateResponse

from . models import Meal
from . forms import MealCreateForm
from . sendfile import send

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect

from django.core.urlresolvers import reverse, reverse_lazy

from datetime import timedelta
from django.utils import timezone

class MealCreateView(FormView):
template_name = "lasana/meal_form.html"
form_class = MealCreateForm

def form_valid(self, form):
expires_in = int(form.cleaned_data['expires_in'])
file = form.cleaned_data['file']

expiration_time = timezone.now() + timedelta(minutes=expires_in)

meal = Meal(file=file, expiration_time=expiration_time)
meal.generate_auto_id()
meal.save()

meal_serve_url = reverse('meal-serve', kwargs={'meal_id': meal.id})
meal_serve_absolute_url = self.request.build_absolute_uri(meal_serve_url)

return TemplateResponse(self.request,
"lasana/meal_create_success.html",
context={'meal': meal,
'meal_serve_absolute_url': meal_serve_absolute_url})


class MealServeView(View):
def get(self, request, *args, **kwargs):
#if there is no such meal, redirect to main page
meal_iter = Meal.objects.filter(id=kwargs['meal_id'])
if len(meal_iter) != 1:
return self.no_meal()

meal = meal_iter[0]

#if meal is there, but has expired, throw it away and redirect to main page too
if meal.is_expired():
meal.delete()
return self.no_meal()
else:
#else, serve the meal
file = meal_iter[0].file
return send(request, file)

def no_meal(self):
return HttpResponseRedirect(reverse('meal-create'))

0 comments on commit 5a16ec1

Please sign in to comment.