Initial commit

This commit is contained in:
Gergely Polonkai 2015-11-26 13:03:46 +01:00
commit cfaa2b2a50
14 changed files with 328 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/venv/
.coverage
db.sqlite3
/htmlcov/

6
CONTRIBUTE.md Normal file
View File

@ -0,0 +1,6 @@
If you want to contribute, put your ideas on the issue board; the
project leads will mark it as a feature, and discussion can start if
it is required or not.
If you find a bug in the code somewhere, feel free to fix it and issue
a pull request against master. The same goes for features.

13
COPYING Normal file
View File

@ -0,0 +1,13 @@
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public
License along with this program. If not, see
<http://www.gnu.org/licenses/>.

13
README.md Normal file
View File

@ -0,0 +1,13 @@
100(ish) words challenge
========================
This is the main project for 100(ish)word challenge, a challenge for
artists of different kinds.
The goal of the site is to present a word for the users every day, and
let them create something based on that word, within a given time
limit. They can then share their work via the site, so other users can
vote for it (if it represents the word by any means).
The project aims to run on Heroku, but testing is done for both Python
2.7 (because of Heroku) and Python 3.4 (because we can).

10
manage.py Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wordchallenge.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

View File

103
wordchallenge/settings.py Normal file
View File

@ -0,0 +1,103 @@
"""
Django settings for wordchallenge project.
Generated by 'django-admin startproject' using Django 1.8.7.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '8$#!)33w0dfn#!ttb2p+)0a*i)n1&q6gwecasfic0+^idz4%qk'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'words',
)
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',
'django.middleware.security.SecurityMiddleware',
)
ROOT_URLCONF = 'wordchallenge.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'wordchallenge.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'

21
wordchallenge/urls.py Normal file
View File

@ -0,0 +1,21 @@
"""wordchallenge URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.8/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Add an import: from blog import urls as blog_urls
2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
"""
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
]

16
wordchallenge/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for wordchallenge project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wordchallenge.settings")
application = get_wsgi_application()

0
words/__init__.py Normal file
View File

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Word',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
],
),
migrations.CreateModel(
name='WordTranslation',
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
('language', models.CharField(db_index=True, max_length=5)),
('translation', models.CharField(null=True, max_length=100)),
('added_at', models.DateTimeField(default=django.utils.timezone.now)),
('added_by', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('word', models.ForeignKey(related_name='translations', to='words.Word')),
],
),
migrations.AlterUniqueTogether(
name='wordtranslation',
unique_together=set([('language', 'translation'), ('word', 'language')]),
),
]

View File

49
words/models.py Normal file
View File

@ -0,0 +1,49 @@
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from django.utils.translation import get_language
class Word(models.Model):
def translation(self, language):
try:
return self.translations.get(language=language)
except WordTranslation.DoesNotExist:
return None
def __str__(self):
try:
return self.translations.get(language=get_language()).translation
except WordTranslation.DoesNotExist:
pass
try:
return self.translations \
.get(language=settings.LANGUAGE_CODE).translation
except WordTranslation.DoesNotExist:
pass
return ""
class WordTranslation(models.Model):
word = models.ForeignKey(Word, related_name='translations')
language = models.CharField(max_length=5, db_index=True)
translation = models.CharField(max_length=100, null=True, blank=False)
added_by = models.ForeignKey(User)
added_at = models.DateTimeField(default=timezone.now)
def clean(self):
from django.core.exceptions import ValidationError
if self.translation is None or self.translation == '':
raise ValidationError('translation must not be empty',
code='translation-empty')
def __str__(self):
return self.translation
class Meta:
unique_together = (
('word', 'language'),
('language', 'translation'),
)

56
words/tests.py Normal file
View File

@ -0,0 +1,56 @@
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.utils.translation import activate
from django.test import TestCase
from .models import Word, WordTranslation
class WordTest(TestCase):
def setUp(self):
user = User.objects.create_user(username='test', password='test')
self.word1 = Word.objects.create()
self.translation1 = WordTranslation.objects.create(
word=self.word1,
language='en-us',
translation='color',
added_by=user)
self.translation2 = WordTranslation.objects.create(
word=self.word1,
language='en-gb',
translation='colour',
added_by=user)
self.translation3 = WordTranslation.objects.create(
word=self.word1,
language='hu-hu',
translation='szín',
added_by=user)
def test_word_str(self):
with self.settings(LANGUAGE_CODE='en-us'):
self.assertEquals("color", self.word1.__str__())
with self.settings(LANGUAGE_CODE='en-gb'):
self.assertEquals('colour', self.word1.__str__())
activate('hu-hu')
self.assertEquals('szín', self.word1.__str__())
with self.settings(LANGUAGE_CODE='es-es'):
activate('is-is')
self.assertEquals('', self.word1.__str__())
def test_word_translation(self):
self.assertEquals('color', self.word1.translation('en-us').translation)
self.assertEquals('colour', self.word1.translation('en-gb').translation)
self.assertIsNone(self.word1.translation('is-is'))
def test_translation_validation(self):
word = WordTranslation()
with self.assertRaises(ValidationError) as ctx:
word.clean()
self.assertEquals('translation-empty', ctx.exception.code)
def test_translation_str(self):
self.assertEquals('color', self.translation1.__str__())