diff --git a/links/__init__.py b/links/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/links/admin.py b/links/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/links/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/links/migrations/0001_initial.py b/links/migrations/0001_initial.py new file mode 100644 index 0000000..f092cd3 --- /dev/null +++ b/links/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Link', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('link', models.URLField(max_length=2048)), + ('base62', models.CharField(max_length=64, null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('clicks', models.IntegerField(default=0)), + ('ip', models.GenericIPAddressField(null=True)), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/links/migrations/0002_auto_20150117_2248.py b/links/migrations/0002_auto_20150117_2248.py new file mode 100644 index 0000000..8f1a83d --- /dev/null +++ b/links/migrations/0002_auto_20150117_2248.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='link', + name='id', + field=models.AutoField(serialize=False, primary_key=True), + preserve_default=True, + ), + ] diff --git a/links/migrations/0003_auto_20150117_2306.py b/links/migrations/0003_auto_20150117_2306.py new file mode 100644 index 0000000..86fff71 --- /dev/null +++ b/links/migrations/0003_auto_20150117_2306.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0002_auto_20150117_2248'), + ] + + operations = [ + migrations.RemoveField( + model_name='link', + name='base62', + ), + migrations.AlterField( + model_name='link', + name='id', + field=models.CharField(max_length=12, serialize=False, primary_key=True), + preserve_default=True, + ), + ] diff --git a/links/migrations/0004_auto_20150117_2338.py b/links/migrations/0004_auto_20150117_2338.py new file mode 100644 index 0000000..46e64c5 --- /dev/null +++ b/links/migrations/0004_auto_20150117_2338.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('links', '0003_auto_20150117_2306'), + ] + + operations = [ + migrations.RenameField( + model_name='link', + old_name='link', + new_name='url', + ), + ] diff --git a/links/migrations/__init__.py b/links/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/links/models.py b/links/models.py new file mode 100644 index 0000000..f99f7e2 --- /dev/null +++ b/links/models.py @@ -0,0 +1,54 @@ +from django.db import models +from django.forms import ModelForm, CharField, TextInput +import random + + +class Link(models.Model): + id = models.CharField(primary_key=True, max_length=12) + url = models.URLField(max_length=2048) + created_at = models.DateTimeField(auto_now_add=True) + clicks = models.IntegerField(default=0) + ip = models.GenericIPAddressField(null=True) + + def __unicode__(self): + return self.url + + def generate_unique_id(self, length=12): + attempts = 0 + id = random_id() + try: + while Link.objects.get(id=id) and attempts < 10: + attempts = attempts + 1 + id = random_id() + except: + pass + return id + + def save(self, *args, **kwargs): + if not self.pk: + self.id = self.generate_unique_id() + super(Link, self).save(*args, **kwargs) + + +class LinkForm(ModelForm): + url = CharField(label='') + class Meta: + model = Link + fields = ['url'] + + +def random_id(): + rand = '' + for i in range(0,12): + rand += int_to_char(random.randint(0,61)); + return rand; + + +def int_to_char(int): + if(int < 10): + char = chr(int + 48) + elif(int < 36): + char = chr(int + 55) + else: + char = chr(int + 61) + return char \ No newline at end of file diff --git a/links/templates/index.html b/links/templates/index.html new file mode 100644 index 0000000..07fa317 --- /dev/null +++ b/links/templates/index.html @@ -0,0 +1,40 @@ + + + + + + minie links! + + + +
+
+ +
+
+ +
+ + {% if short_url %} +
+ + +
+ {% endif %} +
Drag this bookmarklet min.ie to your bookmark bar, or just stick "min.ie/" before any link you want to shrink.
+

Django and Postgres Powered

+
+ + + + + \ No newline at end of file diff --git a/links/tests.py b/links/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/links/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/links/views.py b/links/views.py new file mode 100644 index 0000000..8d3f551 --- /dev/null +++ b/links/views.py @@ -0,0 +1,26 @@ +from django.shortcuts import render, redirect +from django.http import Http404 +from .models import Link, LinkForm +from urlparse import urlparse + +def catchall(request, id): + try: + link = Link.objects.get(id=id) + return redirect(link.url) + except: + parsed = urlparse(id) + if parsed.netloc: + link = Link(url=id) + link.save(); + context = {'form': LinkForm} + context['short_url'] = "http://" + str(request.get_host()) + "/" + str(link.id) + return render(request, 'index.html', context) + raise Http404("Link does not exist") + +def home(request): + context = {'form': LinkForm} + if 'link' in request.POST: + link = Link(link=request.POST['url']) + link.save(); + context['short_url'] = "http://" + str(request.get_host()) + "/" + str(link.id) + return render(request, 'index.html', context) \ No newline at end of file diff --git a/minie/settings.py b/minie/settings.py index e96b364..25fbf8e 100644 --- a/minie/settings.py +++ b/minie/settings.py @@ -17,7 +17,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(__file__)) DEBUG = True TEMPLATE_DEBUG = True -SECRET_KEY = 'uz+*54ipcwwpjjwkt+hb4o_7y0o-%6=@+$rmm2yoaw_7j_=vjw' +SECRET_KEY = os.environ['SECRET_KEY'] ALLOWED_HOSTS = ['*'] @@ -30,16 +30,17 @@ INSTALLED_APPS = ( 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'links', ) MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', +) + +TEMPLATE_DIRS = ( + os.path.join(BASE_DIR, 'links/templates'), ) ROOT_URLCONF = 'minie.urls' diff --git a/minie/urls.py b/minie/urls.py index f1beb5a..e158d95 100644 --- a/minie/urls.py +++ b/minie/urls.py @@ -5,6 +5,7 @@ urlpatterns = patterns('', # Examples: # url(r'^$', 'minie.views.home', name='home'), # url(r'^blog/', include('blog.urls')), - + url(r'^$', 'links.views.home', name='home'), url(r'^admin/', include(admin.site.urls)), + url(r'(.*)', 'links.views.catchall', name='short'), ) diff --git a/static/minie.png b/static/minie.png new file mode 100644 index 0000000..916439a Binary files /dev/null and b/static/minie.png differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..f255595 --- /dev/null +++ b/static/style.css @@ -0,0 +1,229 @@ +/***** Global Settings *****/ + +html, body { +border:0; +margin:0; +padding:0; +} + +body { +font:100%/1.25 arial, helvetica, sans-serif; +} + +/***** Common Formatting *****/ + +h1, h2, h3, h4, h5, h6 { +margin:0; +padding:0; +font-weight:normal; +} + +h1 { +padding:30px 0 25px 0; +letter-spacing:-1px; +font:2em arial, helvetica, sans-serif; +} + +h2 { +padding:20px 0; +letter-spacing:-1px; +font:1.5em arial, helvetica, sans-serif; +} + +h3 { +font:1em arial, helvetica, sans-serif; +font-weight:bold; +} + +p, ul, ol { +margin:0; +padding:0 0 15px 0; +} + +ul, ol { +list-style: disc; +padding:0 0 15px 25px; +} + +blockquote { +margin:22px 40px; +padding:0; +} + +small { +font-size:0.85em; +} + +img { +border:0; +} + +sup { +position:relative; +bottom:0.3em; +vertical-align:baseline; +} + +sub { +position:relative; +bottom:-0.2em; +vertical-align:baseline; +} + +acronym, abbr { +cursor:help; +letter-spacing:1px; +border-bottom:1px dashed; +} + +/***** Links *****/ + +a, a:visited { +text-decoration:none; +} + +/***** Forms *****/ + +form { +margin:0; +padding:0; +display:inline; +} + +input, select, textarea { +font:1em arial, helvetica, sans-serif; +} + +textarea { +line-height:1.25; +} + +label { +cursor:pointer; +} + +/***** Tables *****/ + +table { +border:0; +margin:0 0 18px 0; +padding:0; +} + + table tr td { + padding:2px; + } + +/***** Wrapper *****/ + +#wrap { +width:660px; +margin:0 auto; +} + +/***** Global Classes *****/ + +.clear { clear:both; } + +.float-left { float:left; } +.float-right { float:right; } + +.text-left { text-align:left; } +.text-right { text-align:right; } +.text-center { text-align:center; } +.text-justify { text-align:justify; } + +.bold { font-weight:bold; } +.italic { font-style:italic; } +.underline { border-bottom:1px solid; } +.highlight { background:#ffc; } + +.wrap { width:960px;margin:0 auto; } + +.img-left { float:left;margin:4px 10px 4px 0; } +.img-right { float:right;margin:4px 0 4px 10px; } + +.nopadding { padding:0; } +.noindent { margin-left:0;padding-left:0; } +.nobullet { list-style:none;list-style-image:none; } + +body{ + color: #666; + font-size: 16px; +} +input { + line-height: 24px; +} +#main-submit{ + background: #ff3139; + color: #FFF; + line-height: 22px; + border-bottom: #b92329 solid 1px; + border-right: #b92329 solid 1px; + border-top: #ff3139 solid 1px; + border-left: #ff3139 solid 1px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + font-size: 1.2em; +} +#main-submit:active{ + border-bottom: #ff3139 solid 1px; + border-right: #ff3139 solid 1px; + border-top: #b92329 solid 1px; + border-left: #b92329 solid 1px; +} +#main-box{ + background: #4e9bd1; + width: 570px;color: #FFF; + padding-top: 20px; + padding-bottom: 20px; + border-bottom: #3d79a3 solid 1px; + border-right: #3d79a3 solid 1px; + border-top: #4e9bd1 solid 1px; + border-left: #4e9bd1 solid 1px; + margin: 0 auto; + margin-top: 20px; + text-align: center; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} +#logo-wrap{ + width: 570px; + margin: 0 auto; + margin-top: 20px; + margin-bottom: 20px; +} +#logo-wrap p{ + text-align: right; + font-size: 10px; + color: #ddd; +} +#logo{ + float:right; +} +#info{ + padding-top:15px; + clear:both; + line-height: 24px; +} +#info a{ + color: #4e9bd1; + padding: 4px 8px; + background: #EEE; + border-bottom: #CCC solid 1px; + border-right: #CCC solid 1px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +form ul { + padding: 0; +} + +form li { + display: inline; +} + +#id_url { + width: 400px; +} \ No newline at end of file