├── .bowerrc ├── .gitignore ├── .travis.yml ├── README.md ├── bower.json ├── build-test.txt ├── fabfile.py ├── manage.py ├── pyconkr ├── __init__.py ├── actions.py ├── admin.py ├── context_processors.py ├── fixtures │ └── flatpages.json ├── forms.py ├── helper.py ├── locale │ ├── __init__.py │ ├── en │ │ └── LC_MESSAGES │ │ │ └── django.po │ └── ko │ │ └── LC_MESSAGES │ │ └── django.po ├── migrations │ ├── 0001_initial.py │ ├── 0002_proposal_language.py │ ├── 0003_auto_20160328_1611.py │ ├── 0004_banner.py │ ├── 0005_profile_nationality.py │ ├── 0006_matching_profile.py │ ├── 0007_auto_20160625_1618.py │ ├── 0007_tutorialproposal.py │ ├── 0008_merge.py │ ├── 0009_auto_20160630_1359.py │ ├── 0010_tutorialproposal_type.py │ ├── 0011_auto_20160719_2118.py │ ├── 0012_auto_20160727_2244.py │ ├── 0013_auto_20170428_0007.py │ ├── 0014_auto_20170630_1453.py │ ├── 0015_auto_20170630_1534.py │ ├── 0016_auto_20170701_1757.py │ ├── 0017_programtime_day.py │ ├── 0018_program_is_breaktime.py │ ├── 0019_auto_20170712_2128.py │ ├── 0020_auto_20180611_2132.py │ ├── 0021_tutorialproposal_option.py │ └── __init__.py ├── models.py ├── settings.py ├── static │ ├── css │ │ ├── pyconkr-media.css │ │ ├── pyconkr-summernote.css │ │ ├── pyconkr-teaser.css │ │ ├── pyconkr.css │ │ └── young-coder.css │ ├── image │ │ ├── anonymous.png │ │ ├── dashed-logo.png │ │ ├── dotted-fill-logo.png │ │ ├── dotted-logo.png │ │ ├── etc-badge1.png │ │ ├── etc-badge2.png │ │ ├── favicon.ico │ │ ├── favicon2017.ico │ │ ├── favicon2018.ico │ │ ├── incline-logo.png │ │ ├── naver-d2.png │ │ ├── pycon2018-logo.png │ │ ├── pycon_profile.png │ │ ├── pyconkr-2018-cover.jpg │ │ ├── pyconkr-2018-cover.png │ │ ├── pyconkr-2018-slogan.png │ │ ├── pyconkr-badge.png │ │ ├── pyconkr2017-logo.png │ │ ├── python-white.png │ │ └── stripe-logo.png │ └── js │ │ ├── jquery.quickfit.js │ │ ├── jquery.shuffle.js │ │ ├── rgb-hsv.js │ │ ├── teaser.js │ │ └── young-coder.js ├── templates │ ├── badge │ │ ├── all.html │ │ ├── facebook.html │ │ ├── googleplus.html │ │ └── twitter.html │ ├── banner.html │ ├── base.html │ ├── child_care.html │ ├── dev-robots.txt │ ├── disqus.html │ ├── facebook_script.html │ ├── flatpages │ │ └── default.html │ ├── footer.html │ ├── ga.html │ ├── index.html │ ├── login.html │ ├── login_mailsent.html │ ├── login_notvalidtoken.html │ ├── mail │ │ ├── ticket_registered_html.html │ │ ├── ticket_registered_text.html │ │ ├── token_html.html │ │ └── token_text.html │ ├── nav.html │ ├── pyconkr │ │ ├── announcement_detail.html │ │ ├── announcement_list.html │ │ ├── jobfair_list.html │ │ ├── patron_list.html │ │ ├── profile_detail.html │ │ ├── profile_form.html │ │ ├── program_detail.html │ │ ├── program_form.html │ │ ├── program_list.html │ │ ├── program_preference.html │ │ ├── proposal_detail.html │ │ ├── proposal_form.html │ │ ├── room_detail.html │ │ ├── speaker_detail.html │ │ ├── speaker_form.html │ │ ├── speaker_list.html │ │ ├── sponsor_detail.html │ │ ├── sponsor_list.html │ │ ├── sprintproposal_detail.html │ │ ├── sprintproposal_list.html │ │ ├── tutorialproposal_detail.html │ │ └── tutorialproposal_list.html │ ├── robots.txt │ ├── schedule.html │ ├── sponsors.html │ ├── submenu.html │ └── youngcoder.html ├── tests.py ├── translation.py ├── urls.py ├── views.py └── wsgi.py ├── registration ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── iamporter │ ├── __init__.py │ └── iamporter.py ├── locale │ ├── en │ │ └── LC_MESSAGES │ │ │ └── django.po │ └── ko │ │ └── LC_MESSAGES │ │ └── django.po ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ ├── calculation_attendee.py │ │ ├── delete_login_token.py │ │ └── payment_reconciliation.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20160323_1428.py │ ├── 0003_option_has_additional_price.py │ ├── 0004_registration_additional_price.py │ ├── 0005_option_total.py │ ├── 0006_auto_20160416_1202.py │ ├── 0007_auto_20160416_1217.py │ ├── 0008_auto_20160418_2250.py │ ├── 0009_auto_20160501_2332.py │ ├── 0010_auto_20170428_0007.py │ ├── 0011_auto_20170515_2228.py │ ├── 0012_registration_top_size.py │ ├── 0013_auto_20170616_1446.py │ ├── 0014_auto_20170619_1138.py │ ├── 0015_auto_20170619_1151.py │ ├── 0016_auto_20170619_1155.py │ ├── 0017_auto_20170619_1458.py │ ├── 0018_auto_20170619_1514.py │ ├── 0019_auto_20170630_1534.py │ ├── 0020_auto_20170701_1757.py │ ├── 0021_auto_20170713_1341.py │ ├── 0022_manualpayment.py │ ├── 0023_issue_manager.py │ ├── 0024_add_extra_fields_option.py │ ├── 0025_auto_20180601_0214.py │ ├── 0026_auto_20180607_1241.py │ ├── 0027_auto_20180708_2058.py │ ├── 0027_auto_20180715_2205.py │ ├── 0028_merge_20180723_2159.py │ └── __init__.py ├── models.py ├── static │ ├── js │ │ └── payment.js │ └── stamp.jpg ├── templates │ └── registration │ │ ├── cancellation_result.html │ │ ├── certificates.html │ │ ├── certificates_not_registered.html │ │ ├── certificates_not_visited.html │ │ ├── certificates_sprint.html │ │ ├── certificates_sprint_not_registered.html │ │ ├── certificates_tutorial.html │ │ ├── certificates_tutorial_not_registered.html │ │ ├── certificates_tutorial_not_visited.html │ │ ├── checkin_list.html │ │ ├── info.html │ │ ├── issue_print.html │ │ ├── issue_ticket.html │ │ ├── manual_payment.html │ │ ├── payment.html │ │ ├── payment_babycare.html │ │ ├── payment_youngcoder.html │ │ ├── registration_detail.html │ │ ├── registration_list.html │ │ ├── sprint_checkin.html │ │ ├── sprint_print.html │ │ └── status.html ├── tests.py ├── urls.py └── views.py ├── requirements-dev.txt ├── requirements-prod.txt └── requirements.txt /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory" : "pyconkr/static/components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # dotenv 80 | .env 81 | 82 | # virtualenv 83 | .venv/ 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | # IntelliJ 94 | *.iml 95 | .idea/ 96 | 97 | # Bower 98 | pyconkr/static/components/* 99 | 100 | # TEST db 101 | db.sqlite3 102 | 103 | # macOS 104 | .DS_Store 105 | 106 | # Visual studio code configurations 107 | .vscode/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.6.1" 4 | 5 | # command to install dependencies 6 | install: 7 | - "pip install flake8" 8 | - "pip install -r requirements-dev.txt" 9 | 10 | before_script: 11 | - "export DISPLAY=:99.0" 12 | - "sh -e /etc/init.d/xvfb start" 13 | - sleep 3 # give xvfb some time to start 14 | - python manage.py makemigrations 15 | 16 | # command to run tests 17 | script: 18 | - python manage.py migrate --noinput 19 | - python manage.py test -v 3 20 | 21 | after_success: 22 | - codecov 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A git repository for PyCon Korea 2018 2 | ## Version 11-August-2017 3 | 4 | [![Build Status](https://travis-ci.org/pythonkr/pyconkr-2018.svg?branch=master)](https://travis-ci.org/pythonkr/pyconkr-2018) 5 | 6 | ## Requiremensts 7 | - Python 3.6 8 | 9 | ## Getting started 10 | 11 | ```bash 12 | $ git clone git@github.com:pythonkr/pyconkr-2018.git 13 | $ cd pyconkr-2018 14 | $ pip install -r requirements.txt 15 | $ python manage.py compilemessages 16 | $ python manage.py makemigrations # flatpages 17 | $ python manage.py migrate 18 | $ python manage.py loaddata ./pyconkr/fixtures/flatpages.json 19 | $ bower install 20 | $ python manage.py runserver 21 | ``` 22 | 23 | ## ETC 24 | - 빌드 자동 테스트 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pyconkr", 3 | "dependencies": { 4 | "jquery": "~3.2.1", 5 | "jquery-ui": "~1.12.1", 6 | "select2-bootstrap-css": "~1.4.6", 7 | "html5shiv": "~3.7.2", 8 | "respond": "~1.4.2", 9 | "datetimepicker": "~2.2.4", 10 | "bootstrap": "~3.3.7", 11 | "font-awesome": "~4.7.0", 12 | "select2": "~3.5.4", 13 | "bootstrap-social": "~5.1.1", 14 | "typed.js": "~1.1.1", 15 | "bootstrap-side-navbar": "^1.0.1", 16 | "montserrat-webfont": "^1.0.3", 17 | "datatables.net": "^1.10.15", 18 | "datatables.net-bs": "^2.1.1", 19 | "datatables.net-rowreorder": "^1.2.0", 20 | "datatables.net-rowreorder-bs": "^1.2.0", 21 | "handlebars": "^4.0.10", 22 | "js-cookie": "^2.1.4", 23 | "slick-carousel": "^1.8.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /build-test.txt: -------------------------------------------------------------------------------- 1 | 빌드 자동화 확인 2 | -------------------------------------------------------------------------------- /fabfile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | 4 | from fabric.api import local, run, cd, prefix, env, sudo, settings, shell_env 5 | 6 | env.use_ssh_config = True 7 | env.user = 'pyconkr' 8 | env.hosts = ['pythonkorea1'] 9 | 10 | def deploy(target='dev', sha1=None): 11 | if sha1 is None: 12 | # get current working git sha1 13 | sha1 = local('git rev-parse HEAD', capture=True) 14 | # server code reset to current working sha1 15 | home_dir = '/home/pyconkr/{target}.pycon.kr/pyconkr-2017'.format(target=target) 16 | 17 | if target == 'dev': 18 | python_env = '/home/pyconkr/.pyenv/versions/pyconkr-2017-dev' 19 | else: 20 | python_env = '/home/pyconkr/.pyenv/versions/pyconkr-2017' 21 | 22 | with settings(cd(home_dir), shell_env(DJANGO_SETTINGS_MODULE='pyconkr.settings_prod')): 23 | run('git fetch --all -p') 24 | run('git reset --hard ' + sha1) 25 | run('bower install') 26 | run('%s/bin/pip install -r requirements.txt' % python_env) 27 | run('%s/bin/python manage.py compilemessages' % python_env) 28 | run('%s/bin/python manage.py migrate' % python_env) 29 | run('%s/bin/python manage.py collectstatic --noinput' % python_env) 30 | # worker reload 31 | run('echo r > /var/run/pyconkr-2017-%s.fifo' % target) 32 | 33 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pyconkr.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /pyconkr/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/__init__.py -------------------------------------------------------------------------------- /pyconkr/actions.py: -------------------------------------------------------------------------------- 1 | from .models import (Program, Speaker) 2 | 3 | 4 | def convert_proposal_to_program(modeladmin, request, queryset): 5 | # prepare speaker 6 | for proposal in queryset: 7 | speaker, _ = Speaker.objects.get_or_create(email=proposal.user.email) 8 | program, _ = Program.objects.get_or_create(name=proposal.title) 9 | 10 | # Set initial data 11 | speaker.slug = proposal.user.email 12 | speaker.name = proposal.user.profile.name 13 | speaker.desc = proposal.user.profile.bio 14 | speaker.organization = proposal.user.profile.organization 15 | speaker.save() 16 | 17 | program.brief = proposal.brief 18 | program.desc = proposal.desc 19 | program.difficulty = proposal.difficulty 20 | program.duration = proposal.duration 21 | program.language = proposal.language 22 | program.speakers.clear() 23 | program.speakers.add(speaker) 24 | program.save() 25 | 26 | print(program, speaker) 27 | -------------------------------------------------------------------------------- /pyconkr/context_processors.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | from django.utils import timezone 4 | from django.conf import settings 5 | from django.contrib.flatpages.models import FlatPage 6 | from django.db.models import Count 7 | from django.utils.translation import ugettext_lazy as _ 8 | 9 | from .models import SponsorLevel, Speaker, Banner 10 | 11 | 12 | def default(request): 13 | title = None 14 | # remove i18n_patterns prefix for flatpage 15 | url = request.path.replace('/' + request.LANGUAGE_CODE, '') 16 | if settings.FORCE_SCRIPT_NAME: 17 | url = url[len(settings.FORCE_SCRIPT_NAME):] 18 | base_content = FlatPage.objects.filter(url=url).first() 19 | 20 | submenu = None 21 | menu = OrderedDict([ 22 | ('about', { 23 | 'title': _('About'), 24 | 'icon': 'python', 25 | 'submenu': OrderedDict([ 26 | ('pyconkr', {'title': _('About PyCon Korea 2018')}), 27 | ('coc', {'title': _('Code of Conduct')}), 28 | ('blog', {'title': _('PyCon Korea Blog')}), 29 | ('announcements', {'title': _('Announcements')}), 30 | ('sponsor', {'title': _('Sponsors')}), 31 | ('patron', {'title': _('Patrons')}), 32 | ('sponsorship', {'title': _('Sponsorship')}), 33 | ('staff', {'title': _('Staff')}), 34 | ('contact', {'title': _('Contact')}), 35 | ]), 36 | }), 37 | ('program', { 38 | 'title': _('Programs'), 39 | 'icon': 'calendar', 40 | 'submenu': OrderedDict([ 41 | ('schedule', {'title': _('Schedule')}), 42 | ('list', {'title': _('Program list')}), 43 | ('keynote', {'title': _('Keynotes')}), 44 | ('speaker', {'title': _('Speakers')}), 45 | ('tutorial', {'title': _('Tutorial')}), 46 | ('sprint', {'title': _('Sprint')}), 47 | ('youngcoder', {'title': _('Young Coder')}), 48 | ('child_care', {'title': _('Child Care')}), 49 | ('lightning_talk', {'title': _('Lightning talk')}), 50 | ('ost', {'title': _('Open Spaces')}), 51 | ('health', {'title': _('Health')}), 52 | ]), 53 | }), 54 | ('venue', { 55 | 'title': _('Venue'), 56 | 'icon': 'map-marker', 57 | 'submenu': OrderedDict([ 58 | ('map', {'title': _('Venue Map')}), 59 | ('transportation', {'title': _('Transportation')}), 60 | ]), 61 | }), 62 | ('cfp', { 63 | 'title': _('Proposal'), 64 | 'icon': 'edit', 65 | 'submenu': OrderedDict([ 66 | ('cfp', {'title': _('Call for proposals')}), 67 | ('howto', {'title': _('How to propose')}), 68 | ]), 69 | }), 70 | ('registration', { 71 | 'title': _('Registration'), 72 | 'icon': 'book', 73 | 'submenu': OrderedDict([ 74 | ('information', {'title': _('Information')}), 75 | ('purchase', {'title': _('Purchase a ticket')}), 76 | ('finacial-aid', {'title': _('Financial Aid')}), 77 | ('visa', {'title': _('Visa Sponsing')}), 78 | ]), 79 | }), 80 | ]) 81 | 82 | for k, v in menu.items(): 83 | path = '/{}/'.format(k) 84 | 85 | if url.startswith(path): 86 | v['active'] = True 87 | title = v['title'] 88 | 89 | if 'submenu' in v: 90 | submenu = v['submenu'] 91 | 92 | for sk, sv in v['submenu'].items(): 93 | sv['path'] = '{}{}/'.format(path, sk) 94 | subpath = sv['path'] 95 | 96 | if url == subpath: 97 | sv['active'] = True 98 | title = sv['title'] 99 | 100 | now = timezone.now() 101 | banners = Banner.objects.filter(begin__lte=now, end__gte=now) 102 | 103 | c = { 104 | 'menu': menu, 105 | 'submenu': submenu, 106 | 'banners': banners, 107 | 'title': title, 108 | 'domain': settings.DOMAIN, 109 | 'base_content': base_content.content if base_content else '', 110 | } 111 | return c 112 | 113 | 114 | def profile(request): 115 | speaker = None 116 | programs = None 117 | 118 | if request.user.is_authenticated(): 119 | speaker = Speaker.objects.filter(email=request.user.email).first() 120 | if speaker: 121 | programs = speaker.program_set.all() 122 | 123 | return { 124 | 'my_speaker': speaker, 125 | 'my_programs': programs, 126 | } 127 | 128 | 129 | def sponsors(request): 130 | levels = SponsorLevel.objects.annotate( 131 | num_sponsors=Count('sponsor')).filter(num_sponsors__gt=0) 132 | 133 | return { 134 | 'levels': levels, 135 | } 136 | -------------------------------------------------------------------------------- /pyconkr/helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | 4 | from django.core.mail import EmailMultiAlternatives 5 | from django.http import HttpResponse 6 | from django.template.loader import render_to_string 7 | from django.utils.translation import ugettext_lazy as _ 8 | 9 | 10 | def sendEmailToken(request, token): 11 | title = _('PyCon Korea 2018 one-time login token') 12 | sender = _('PyCon Korea 2018') + '' 13 | html = render_to_string('mail/token_html.html', {'token': token}, request) 14 | text = render_to_string('mail/token_text.html', {'token': token}, request) 15 | 16 | msg = EmailMultiAlternatives( 17 | title, 18 | text, 19 | sender, 20 | [token.email]) 21 | msg.attach_alternative(html, "text/html") 22 | msg.send(fail_silently=False) 23 | 24 | 25 | def is_pycon_user(email): 26 | return str.endswith(email, '@pycon.kr') 27 | 28 | 29 | def render_json(data_dict): 30 | return HttpResponse(json.dumps(data_dict), 31 | 'application/javascript') 32 | 33 | 34 | def render_template_json(template, context): 35 | return HttpResponse(render_to_string(template, context), 36 | 'application/javascript') 37 | 38 | 39 | def render_io_error(reason): 40 | response = HttpResponse(reason) 41 | response.status_code = 406 42 | return response 43 | -------------------------------------------------------------------------------- /pyconkr/locale/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/locale/__init__.py -------------------------------------------------------------------------------- /pyconkr/migrations/0002_proposal_language.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-03-28 13:35 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='proposal', 17 | name='language', 18 | field=models.CharField(choices=[(b'E', 'English'), (b'K', 'Korean')], default=b'E', max_length=1), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyconkr/migrations/0003_auto_20160328_1611.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-03-28 16:11 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | ('pyconkr', '0002_proposal_language'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AlterField( 18 | model_name='proposal', 19 | name='user', 20 | field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /pyconkr/migrations/0004_banner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-04-02 01:43 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import sorl.thumbnail.fields 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyconkr', '0003_auto_20160328_1611'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Banner', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=100)), 21 | ('url', models.CharField(blank=True, max_length=255, null=True)), 22 | ('image', sorl.thumbnail.fields.ImageField(upload_to=b'banner')), 23 | ('desc', models.TextField(blank=True, null=True)), 24 | ('desc_ko', models.TextField(blank=True, null=True)), 25 | ('desc_en', models.TextField(blank=True, null=True)), 26 | ('begin', models.DateTimeField(blank=True, null=True)), 27 | ('end', models.DateTimeField(blank=True, null=True)), 28 | ], 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /pyconkr/migrations/0005_profile_nationality.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-05-01 14:38 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0004_banner'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='profile', 17 | name='nationality', 18 | field=models.CharField(blank=True, max_length=100, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyconkr/migrations/0006_matching_profile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-06-18 01:09 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0005_profile_nationality'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='program', 17 | name='brief', 18 | field=models.TextField(blank=True, null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='program', 22 | name='difficulty', 23 | field=models.CharField(choices=[(b'B', 'Beginner'), (b'I', 'Intermediate'), (b'E', 'Experienced')], default=b'B', max_length=1), 24 | ), 25 | migrations.AddField( 26 | model_name='program', 27 | name='duration', 28 | field=models.CharField(choices=[(b'S', '25 mins'), (b'L', '40 mins')], default=b'S', max_length=1), 29 | ), 30 | migrations.AddField( 31 | model_name='speaker', 32 | name='organization', 33 | field=models.CharField(blank=True, max_length=100, null=True), 34 | ), 35 | migrations.AlterField( 36 | model_name='program', 37 | name='language', 38 | field=models.CharField(choices=[(b'E', 'English'), (b'K', 'Korean')], default=b'E', max_length=1), 39 | ), 40 | migrations.AlterField( 41 | model_name='program', 42 | name='name', 43 | field=models.CharField(db_index=True, max_length=255), 44 | ), 45 | migrations.AlterField( 46 | model_name='program', 47 | name='name_en', 48 | field=models.CharField(db_index=True, max_length=255, null=True), 49 | ), 50 | migrations.AlterField( 51 | model_name='program', 52 | name='name_ko', 53 | field=models.CharField(db_index=True, max_length=255, null=True), 54 | ), 55 | ] 56 | -------------------------------------------------------------------------------- /pyconkr/migrations/0007_auto_20160625_1618.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-06-25 07:18 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('pyconkr', '0006_matching_profile'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Preference', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('program', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pyconkr.Program')), 23 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 24 | ], 25 | ), 26 | migrations.AlterUniqueTogether( 27 | name='preference', 28 | unique_together=set([('user', 'program')]), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /pyconkr/migrations/0007_tutorialproposal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2016-06-25 06:41 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('pyconkr', '0006_matching_profile'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='TutorialProposal', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('title', models.CharField(max_length=255)), 23 | ('brief', models.TextField(max_length=1000)), 24 | ('desc', models.TextField(max_length=4000)), 25 | ('comment', models.TextField(blank=True, max_length=4000, null=True)), 26 | ('difficulty', models.CharField(choices=[(b'B', 'Beginner'), (b'I', 'Intermediate'), (b'E', 'Experienced')], max_length=1)), 27 | ('duration', models.CharField(choices=[(b'S', '1 hour'), (b'M', '2 hours'), (b'L', '4 hours')], max_length=1)), 28 | ('language', models.CharField(choices=[(b'E', 'English'), (b'K', 'Korean')], default=b'E', max_length=1)), 29 | ('capacity', models.CharField(choices=[(b'S', '10 people'), (b'M', '45 people'), (b'L', '100 people')], max_length=1)), 30 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 31 | ], 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /pyconkr/migrations/0008_merge.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-06-25 08:38 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0007_auto_20160625_1618'), 12 | ('pyconkr', '0007_tutorialproposal'), 13 | ] 14 | 15 | operations = [ 16 | ] 17 | -------------------------------------------------------------------------------- /pyconkr/migrations/0009_auto_20160630_1359.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-06-30 04:59 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0008_merge'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='programcategory', 17 | name='show_in_list', 18 | field=models.BooleanField(default=True), 19 | ), 20 | migrations.AddField( 21 | model_name='programcategory', 22 | name='show_in_mobile', 23 | field=models.BooleanField(default=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /pyconkr/migrations/0010_tutorialproposal_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-07-19 11:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0009_auto_20160630_1359'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='tutorialproposal', 17 | name='type', 18 | field=models.CharField(choices=[(b'T', 'Tutorial'), (b'S', 'Sprint')], default=b'T', max_length=1), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyconkr/migrations/0011_auto_20160719_2118.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-07-19 12:18 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('pyconkr', '0010_tutorialproposal_type'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='TutorialCheckin', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('tutorial', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pyconkr.TutorialProposal')), 23 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 24 | ], 25 | ), 26 | migrations.AlterUniqueTogether( 27 | name='tutorialcheckin', 28 | unique_together=set([('user', 'tutorial')]), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /pyconkr/migrations/0012_auto_20160727_2244.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-07-27 13:44 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0011_auto_20160719_2118'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='tutorialproposal', 17 | name='desc', 18 | field=models.TextField(), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyconkr/migrations/0013_auto_20170428_0007.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-04-27 15:07 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import sorl.thumbnail.fields 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyconkr', '0012_auto_20160727_2244'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='banner', 18 | name='image', 19 | field=sorl.thumbnail.fields.ImageField(upload_to='banner'), 20 | ), 21 | migrations.AlterField( 22 | model_name='profile', 23 | name='image', 24 | field=sorl.thumbnail.fields.ImageField(blank=True, null=True, upload_to='profile'), 25 | ), 26 | migrations.AlterField( 27 | model_name='program', 28 | name='difficulty', 29 | field=models.CharField(choices=[('B', 'Beginner'), ('I', 'Intermediate'), ('E', 'Experienced')], default='B', max_length=1), 30 | ), 31 | migrations.AlterField( 32 | model_name='program', 33 | name='duration', 34 | field=models.CharField(choices=[('S', '25 mins'), ('L', '40 mins')], default='S', max_length=1), 35 | ), 36 | migrations.AlterField( 37 | model_name='program', 38 | name='language', 39 | field=models.CharField(choices=[('E', 'English'), ('K', 'Korean')], default='E', max_length=1), 40 | ), 41 | migrations.AlterField( 42 | model_name='proposal', 43 | name='difficulty', 44 | field=models.CharField(choices=[('B', 'Beginner'), ('I', 'Intermediate'), ('E', 'Experienced')], max_length=1), 45 | ), 46 | migrations.AlterField( 47 | model_name='proposal', 48 | name='duration', 49 | field=models.CharField(choices=[('S', '25 mins'), ('L', '40 mins')], max_length=1), 50 | ), 51 | migrations.AlterField( 52 | model_name='proposal', 53 | name='language', 54 | field=models.CharField(choices=[('E', 'English'), ('K', 'Korean')], default='E', max_length=1), 55 | ), 56 | migrations.AlterField( 57 | model_name='speaker', 58 | name='image', 59 | field=models.ImageField(blank=True, null=True, upload_to='speaker'), 60 | ), 61 | migrations.AlterField( 62 | model_name='sponsor', 63 | name='image', 64 | field=models.ImageField(blank=True, null=True, upload_to='sponsor'), 65 | ), 66 | migrations.AlterField( 67 | model_name='tutorialproposal', 68 | name='capacity', 69 | field=models.CharField(choices=[('S', '10 people'), ('M', '45 people'), ('L', '100 people')], max_length=1), 70 | ), 71 | migrations.AlterField( 72 | model_name='tutorialproposal', 73 | name='difficulty', 74 | field=models.CharField(choices=[('B', 'Beginner'), ('I', 'Intermediate'), ('E', 'Experienced')], max_length=1), 75 | ), 76 | migrations.AlterField( 77 | model_name='tutorialproposal', 78 | name='duration', 79 | field=models.CharField(choices=[('S', '1 hour'), ('M', '2 hours'), ('L', '4 hours')], max_length=1), 80 | ), 81 | migrations.AlterField( 82 | model_name='tutorialproposal', 83 | name='language', 84 | field=models.CharField(choices=[('E', 'English'), ('K', 'Korean')], default='E', max_length=1), 85 | ), 86 | migrations.AlterField( 87 | model_name='tutorialproposal', 88 | name='type', 89 | field=models.CharField(choices=[('T', 'Tutorial'), ('S', 'Sprint')], default='T', max_length=1), 90 | ), 91 | ] 92 | -------------------------------------------------------------------------------- /pyconkr/migrations/0014_auto_20170630_1453.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-06-30 05:53 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('pyconkr', '0013_auto_20170428_0007'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='SprintCheckin', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ], 23 | ), 24 | migrations.CreateModel( 25 | name='SprintProposal', 26 | fields=[ 27 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 28 | ('title', models.CharField(max_length=255)), 29 | ('language', models.CharField(max_length=255)), 30 | ('project_url', models.CharField(max_length=1024)), 31 | ('project_brief', models.TextField(max_length=1000)), 32 | ('contribution_desc', models.TextField()), 33 | ('comment', models.TextField(blank=True, max_length=4000, null=True)), 34 | ('confirmed', models.BooleanField(default=False)), 35 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ], 37 | ), 38 | migrations.RemoveField( 39 | model_name='tutorialproposal', 40 | name='type', 41 | ), 42 | migrations.AddField( 43 | model_name='tutorialproposal', 44 | name='confirmed', 45 | field=models.BooleanField(default=False), 46 | ), 47 | migrations.AddField( 48 | model_name='sprintcheckin', 49 | name='sprint', 50 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pyconkr.SprintProposal'), 51 | ), 52 | migrations.AddField( 53 | model_name='sprintcheckin', 54 | name='user', 55 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 56 | ), 57 | migrations.AlterUniqueTogether( 58 | name='sprintcheckin', 59 | unique_together=set([('user', 'sprint')]), 60 | ), 61 | ] 62 | -------------------------------------------------------------------------------- /pyconkr/migrations/0015_auto_20170630_1534.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-06-30 06:34 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0014_auto_20170630_1453'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterUniqueTogether( 16 | name='sprintcheckin', 17 | unique_together=set([]), 18 | ), 19 | migrations.RemoveField( 20 | model_name='sprintcheckin', 21 | name='sprint', 22 | ), 23 | migrations.RemoveField( 24 | model_name='sprintcheckin', 25 | name='user', 26 | ), 27 | migrations.RemoveField( 28 | model_name='sprintproposal', 29 | name='user', 30 | ), 31 | migrations.RemoveField( 32 | model_name='tutorialproposal', 33 | name='confirmed', 34 | ), 35 | migrations.AddField( 36 | model_name='tutorialproposal', 37 | name='type', 38 | field=models.CharField(choices=[('T', 'Tutorial'), ('S', 'Sprint')], default='T', max_length=1), 39 | ), 40 | migrations.DeleteModel( 41 | name='SprintCheckin', 42 | ), 43 | migrations.DeleteModel( 44 | name='SprintProposal', 45 | ), 46 | ] 47 | -------------------------------------------------------------------------------- /pyconkr/migrations/0016_auto_20170701_1757.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.1 on 2017-07-01 08:57 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('pyconkr', '0015_auto_20170630_1534'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='SprintCheckin', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ], 23 | ), 24 | migrations.CreateModel( 25 | name='SprintProposal', 26 | fields=[ 27 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 28 | ('title', models.CharField(max_length=255)), 29 | ('language', models.CharField(max_length=255)), 30 | ('project_url', models.CharField(max_length=1024)), 31 | ('project_brief', models.TextField(max_length=1000)), 32 | ('contribution_desc', models.TextField()), 33 | ('comment', models.TextField(blank=True, max_length=4000, null=True)), 34 | ('confirmed', models.BooleanField(default=False)), 35 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ], 37 | ), 38 | migrations.RemoveField( 39 | model_name='tutorialproposal', 40 | name='type', 41 | ), 42 | migrations.AddField( 43 | model_name='tutorialproposal', 44 | name='confirmed', 45 | field=models.BooleanField(default=False), 46 | ), 47 | migrations.AddField( 48 | model_name='sprintcheckin', 49 | name='sprint', 50 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pyconkr.SprintProposal'), 51 | ), 52 | migrations.AddField( 53 | model_name='sprintcheckin', 54 | name='user', 55 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 56 | ), 57 | migrations.AlterUniqueTogether( 58 | name='sprintcheckin', 59 | unique_together=set([('user', 'sprint')]), 60 | ), 61 | ] 62 | -------------------------------------------------------------------------------- /pyconkr/migrations/0017_programtime_day.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-07-12 10:14 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('pyconkr', '0016_auto_20170701_1757'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AddField( 17 | model_name='programtime', 18 | name='day', 19 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pyconkr.ProgramDate'), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /pyconkr/migrations/0018_program_is_breaktime.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-07-12 12:26 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0017_programtime_day'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='program', 17 | name='is_breaktime', 18 | field=models.BooleanField(default=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyconkr/migrations/0019_auto_20170712_2128.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-07-12 12:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0018_program_is_breaktime'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='program', 17 | name='is_breaktime', 18 | field=models.BooleanField(default=False), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /pyconkr/migrations/0020_auto_20180611_2132.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.13 on 2018-06-11 12:32 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('pyconkr', '0019_auto_20170712_2128'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='sponsor', 17 | options={'ordering': ['deposit_time', 'id']}, 18 | ), 19 | migrations.AddField( 20 | model_name='sponsor', 21 | name='deposit_time', 22 | field=models.DateTimeField(blank=True, null=True), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /pyconkr/migrations/0021_tutorialproposal_option.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.11 on 2018-07-20 06:20 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('registration', '0027_auto_20180708_2058'), 13 | ('pyconkr', '0020_auto_20180611_2132'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AddField( 18 | model_name='tutorialproposal', 19 | name='begin_date', 20 | field=models.DateField(blank=True, null=True), 21 | ), 22 | migrations.AddField( 23 | model_name='tutorialproposal', 24 | name='begin_time', 25 | field=models.TimeField(blank=True, null=True), 26 | ), 27 | migrations.AddField( 28 | model_name='tutorialproposal', 29 | name='end_date', 30 | field=models.DateField(blank=True, null=True), 31 | ), 32 | migrations.AddField( 33 | model_name='tutorialproposal', 34 | name='end_time', 35 | field=models.TimeField(blank=True, null=True), 36 | ), 37 | migrations.AddField( 38 | model_name='tutorialproposal', 39 | name='option', 40 | field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='registration.Option', verbose_name='구매 티켓 종류'), 41 | ), 42 | ] 43 | -------------------------------------------------------------------------------- /pyconkr/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/migrations/__init__.py -------------------------------------------------------------------------------- /pyconkr/static/css/pyconkr-media.css: -------------------------------------------------------------------------------- 1 | @media (max-width: 767px) { 2 | .navbar { 3 | top: 0px; 4 | width: 100%; 5 | z-index: 50; 6 | } 7 | .navbar-nav { 8 | margin-top: 4px; 9 | } 10 | .navbar .navbar-toggle { 11 | position: fixed; 12 | z-index: 100; 13 | top: 12px; 14 | right: 12px; 15 | margin: 0; 16 | background: rgba(255,255,255,0.95); 17 | } 18 | .navbar .navbar-collapse { 19 | background: rgba(255,255,255,0.98); 20 | top: 0px; 21 | position: fixed; 22 | width: 100%; 23 | min-height: 1024px; 24 | max-height: 1024px; 25 | } 26 | 27 | .navbar .navbar-nav>.active>a, 28 | .navbar .navbar-nav>.active>a:hover, 29 | .navbar .navbar-nav>.active>a:focus { 30 | border-bottom: none; 31 | background-color: #aaa; 32 | } 33 | 34 | .navbar-translucent { 35 | } 36 | .navbar-translucent .navbar-toggle{ 37 | position: absolute; 38 | background: rgba(0,0,0,0.5); 39 | } 40 | .navbar-translucent .navbar-collapse { 41 | z-index: 10; 42 | background: rgba(0,0,0,0.9); 43 | } 44 | .navbar-translucent .dropdown-menu>li>a { 45 | color: #fff; 46 | } 47 | .navbar-translucent .nav>li>a:hover, 48 | .navbar-translucent .nav>li>a:focus, 49 | .navbar-translucent .dropdown-menu>li>a:hover, 50 | .navbar-translucent .dropdown-menu>li>a:focus { 51 | background-color: #555; 52 | } 53 | .navbar-nav>li>a { 54 | padding: 10px 0 15px 15px; 55 | font-size: 1.5rem; 56 | line-height: 30px; 57 | } 58 | .navbar-nav .open .dropdown-menu>li>a { 59 | font-size: 1.2rem; 60 | line-height: 30px; 61 | } 62 | .frontpage .sky { 63 | height: 425px; 64 | } 65 | .footer .col { 66 | text-align: center; 67 | } 68 | .titlebar h1 { 69 | font-size: 2rem; 70 | } 71 | .sponsor img { 72 | max-width: 100%; 73 | } 74 | } 75 | 76 | @media (max-width: 640px) { 77 | .frontpage .slogan h1 { 78 | font-size: 4rem; 79 | } 80 | .frontpage .slogan h3 { 81 | font-size: 1.5rem; 82 | } 83 | } 84 | 85 | @media (max-width: 480px) { 86 | .frontpage .sky { 87 | height: 340px; 88 | } 89 | .container { 90 | padding-left: 20px; 91 | padding-right: 20px; 92 | } 93 | .container>.navbar-header, 94 | .container>.navbar-collapse { 95 | margin-left: -5px; 96 | margin-right: -5px; 97 | } 98 | 99 | .frontpage .slogan h1 { 100 | font-size: 3rem; 101 | margin-top: 30px; 102 | } 103 | .frontpage .slogan h3 { 104 | font-size: 1rem; 105 | } 106 | 107 | .well { 108 | margin: 14px -12px; 109 | } 110 | 111 | .jobfair dt img { 112 | width: auto; 113 | height: 32px; 114 | } 115 | 116 | .box-slick { 117 | width: 100%; 118 | padding: 30px 20px; 119 | } 120 | 121 | .box-section { 122 | padding: 10px; 123 | font-size: 14px; 124 | } 125 | 126 | .ticket-left { 127 | width: 10em; 128 | } 129 | } 130 | 131 | @media (min-width: 768px) { 132 | .container { 133 | width: auto; 134 | } 135 | } 136 | 137 | @media (min-width: 992px) { 138 | .container { 139 | width: 970px; 140 | } 141 | } 142 | 143 | @media (min-width: 1280px) { 144 | .container { 145 | width: 970px; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /pyconkr/static/css/pyconkr-summernote.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-bottom: 0; 3 | } 4 | -------------------------------------------------------------------------------- /pyconkr/static/css/young-coder.css: -------------------------------------------------------------------------------- 1 | .board { 2 | width: 90%; 3 | margin: 60px auto; 4 | height: 2500px; 5 | background: #fff; 6 | } 7 | 8 | .board .nav-tabs { 9 | position: relative; 10 | margin: 40px auto; 11 | margin-bottom: 0; 12 | box-sizing: border-box; 13 | 14 | } 15 | 16 | .board > div.board-inner { 17 | /*background-size: 30%;*/ 18 | } 19 | 20 | p.narrow { 21 | width: 60%; 22 | margin: 10px auto; 23 | } 24 | 25 | .liner { 26 | height: 2px; 27 | background: #ddd; 28 | position: absolute; 29 | width: 80%; 30 | margin: 0 auto; 31 | left: 0; 32 | right: 0; 33 | top: 50%; 34 | z-index: 1; 35 | } 36 | 37 | .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { 38 | color: #555555; 39 | cursor: default; 40 | border: 0; 41 | border-bottom-color: transparent; 42 | } 43 | 44 | span.round-tabs { 45 | width: 70px; 46 | height: 70px; 47 | line-height: 70px; 48 | display: inline-block; 49 | border-radius: 100px; 50 | background: white; 51 | z-index: 2; 52 | position: absolute; 53 | left: 0; 54 | text-align: center; 55 | font-size: 25px; 56 | } 57 | 58 | span.round-tabs.one { 59 | color: rgb(34, 194, 34); 60 | border: 2px solid rgb(34, 194, 34); 61 | } 62 | 63 | li.active span.round-tabs.one { 64 | background: #fff !important; 65 | border: 2px solid #ddd; 66 | color: rgb(34, 194, 34); 67 | } 68 | 69 | span.round-tabs.two { 70 | color: #febe29; 71 | border: 2px solid #febe29; 72 | } 73 | 74 | li.active span.round-tabs.two { 75 | background: #fff !important; 76 | border: 2px solid #ddd; 77 | color: #febe29; 78 | } 79 | 80 | span.round-tabs.three { 81 | color: #3e5e9a; 82 | border: 2px solid #3e5e9a; 83 | } 84 | 85 | li.active span.round-tabs.three { 86 | background: #fff !important; 87 | border: 2px solid #ddd; 88 | color: #3e5e9a; 89 | } 90 | 91 | span.round-tabs.four { 92 | color: #f1685e; 93 | border: 2px solid #f1685e; 94 | } 95 | 96 | li.active span.round-tabs.four { 97 | background: #fff !important; 98 | border: 2px solid #ddd; 99 | color: #f1685e; 100 | } 101 | 102 | span.round-tabs.five { 103 | color: #999; 104 | border: 2px solid #999; 105 | } 106 | 107 | li.active span.round-tabs.five { 108 | background: #fff !important; 109 | border: 2px solid #ddd; 110 | color: #999; 111 | } 112 | 113 | .nav-tabs > li.active > a span.round-tabs { 114 | background: #fafafa; 115 | } 116 | 117 | .nav-tabs > li { 118 | width: 25%; 119 | } 120 | 121 | li:after { 122 | content: " "; 123 | position: absolute; 124 | left: 45%; 125 | opacity: 0; 126 | margin: 0 auto; 127 | bottom: 0px; 128 | border: 5px solid transparent; 129 | border-bottom-color: #ddd; 130 | transition: 0.1s ease-in-out; 131 | 132 | } 133 | 134 | li.active:after { 135 | content: " "; 136 | position: absolute; 137 | left: 45%; 138 | opacity: 1; 139 | margin: 0 auto; 140 | bottom: 0px; 141 | border: 10px solid transparent; 142 | border-bottom-color: #ddd; 143 | 144 | } 145 | 146 | .nav-tabs > li a { 147 | width: 70px; 148 | height: 70px; 149 | margin: 20px auto; 150 | border-radius: 100%; 151 | padding: 0; 152 | } 153 | 154 | .nav-tabs > li a:hover { 155 | background: transparent; 156 | } 157 | 158 | .tab-content { 159 | } 160 | 161 | .tab-pane { 162 | position: relative; 163 | padding-top: 50px; 164 | } 165 | 166 | .tab-content .head { 167 | font-family: 'Roboto Condensed', sans-serif; 168 | font-size: 25px; 169 | text-transform: uppercase; 170 | padding-bottom: 10px; 171 | } 172 | 173 | .btn-outline-rounded { 174 | padding: 10px 40px; 175 | margin: 20px 0; 176 | border: 2px solid transparent; 177 | border-radius: 25px; 178 | } 179 | 180 | .youngcoder-logo { 181 | height: 100px; 182 | } 183 | 184 | @media ( max-width: 585px ) { 185 | .board { 186 | width: 90%; 187 | height: auto !important; 188 | } 189 | 190 | span.round-tabs { 191 | font-size: 16px; 192 | width: 50px; 193 | height: 50px; 194 | line-height: 50px; 195 | } 196 | 197 | .tab-content .head { 198 | font-size: 20px; 199 | } 200 | 201 | .nav-tabs > li a { 202 | width: 50px; 203 | height: 50px; 204 | line-height: 50px; 205 | } 206 | 207 | li.active:after { 208 | content: " "; 209 | position: absolute; 210 | left: 35%; 211 | } 212 | 213 | .btn-outline-rounded { 214 | padding: 12px 20px; 215 | } 216 | } -------------------------------------------------------------------------------- /pyconkr/static/image/anonymous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/anonymous.png -------------------------------------------------------------------------------- /pyconkr/static/image/dashed-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/dashed-logo.png -------------------------------------------------------------------------------- /pyconkr/static/image/dotted-fill-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/dotted-fill-logo.png -------------------------------------------------------------------------------- /pyconkr/static/image/dotted-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/dotted-logo.png -------------------------------------------------------------------------------- /pyconkr/static/image/etc-badge1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/etc-badge1.png -------------------------------------------------------------------------------- /pyconkr/static/image/etc-badge2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/etc-badge2.png -------------------------------------------------------------------------------- /pyconkr/static/image/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/favicon.ico -------------------------------------------------------------------------------- /pyconkr/static/image/favicon2017.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/favicon2017.ico -------------------------------------------------------------------------------- /pyconkr/static/image/favicon2018.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/favicon2018.ico -------------------------------------------------------------------------------- /pyconkr/static/image/incline-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/incline-logo.png -------------------------------------------------------------------------------- /pyconkr/static/image/naver-d2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/naver-d2.png -------------------------------------------------------------------------------- /pyconkr/static/image/pycon2018-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pycon2018-logo.png -------------------------------------------------------------------------------- /pyconkr/static/image/pycon_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pycon_profile.png -------------------------------------------------------------------------------- /pyconkr/static/image/pyconkr-2018-cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pyconkr-2018-cover.jpg -------------------------------------------------------------------------------- /pyconkr/static/image/pyconkr-2018-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pyconkr-2018-cover.png -------------------------------------------------------------------------------- /pyconkr/static/image/pyconkr-2018-slogan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pyconkr-2018-slogan.png -------------------------------------------------------------------------------- /pyconkr/static/image/pyconkr-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pyconkr-badge.png -------------------------------------------------------------------------------- /pyconkr/static/image/pyconkr2017-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/pyconkr2017-logo.png -------------------------------------------------------------------------------- /pyconkr/static/image/python-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/python-white.png -------------------------------------------------------------------------------- /pyconkr/static/image/stripe-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/pyconkr/static/image/stripe-logo.png -------------------------------------------------------------------------------- /pyconkr/static/js/jquery.quickfit.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | var Quickfit, QuickfitHelper, defaults, pluginName; 3 | 4 | pluginName = 'quickfit'; 5 | 6 | defaults = { 7 | min: 8, 8 | max: 12, 9 | tolerance: 0.02, 10 | truncate: false, 11 | width: null, 12 | sampleNumberOfLetters: 10, 13 | sampleFontSize: 12 14 | }; 15 | QuickfitHelper = (function () { 16 | 17 | var sharedInstance = null; 18 | 19 | QuickfitHelper.instance = function (options) { 20 | if (!sharedInstance) { 21 | sharedInstance = new QuickfitHelper(options); 22 | } 23 | return sharedInstance; 24 | }; 25 | 26 | function QuickfitHelper(options) { 27 | this.options = options; 28 | 29 | this.item = $(''); 30 | this.item.css({ 31 | position: 'absolute', 32 | left: '-1000px', 33 | top: '-1000px', 34 | 'font-size': "" + this.options.sampleFontSize + "px" 35 | }); 36 | $('body').append(this.item); 37 | 38 | this.meassures = {}; 39 | } 40 | 41 | QuickfitHelper.prototype.getMeassure = function (letter) { 42 | var currentMeassure; 43 | currentMeassure = this.meassures[letter]; 44 | if (!currentMeassure) { 45 | currentMeassure = this.setMeassure(letter); 46 | } 47 | return currentMeassure; 48 | }; 49 | 50 | QuickfitHelper.prototype.setMeassure = function (letter) { 51 | var currentMeassure, index, sampleLetter, text, _ref; 52 | 53 | text = ''; 54 | sampleLetter = letter === ' ' ? ' ' : letter; 55 | 56 | for (index = 0, _ref = this.options.sampleNumberOfLetters - 1; 0 <= _ref ? index <= _ref : index >= _ref; 0 <= _ref ? index++ : index--) { 57 | text += sampleLetter; 58 | } 59 | 60 | this.item.html(text); 61 | currentMeassure = this.item.width() / this.options.sampleNumberOfLetters / this.options.sampleFontSize; 62 | this.meassures[letter] = currentMeassure; 63 | 64 | return currentMeassure; 65 | }; 66 | 67 | return QuickfitHelper; 68 | 69 | })(); 70 | 71 | Quickfit = (function () { 72 | 73 | function Quickfit(element, options) { 74 | this.$element = element; 75 | this.options = $.extend({}, defaults, options); 76 | this.$element = $(this.$element); 77 | this._defaults = defaults; 78 | this._name = pluginName; 79 | this.quickfitHelper = QuickfitHelper.instance(this.options); 80 | } 81 | 82 | Quickfit.prototype.fit = function () { 83 | var elementWidth; 84 | if (!this.options.width) { 85 | elementWidth = this.$element.width(); 86 | this.options.width = elementWidth - this.options.tolerance * elementWidth; 87 | } 88 | if (this.text = this.$element.attr('data-quickfit')) { 89 | this.previouslyTruncated = true; 90 | } else { 91 | this.text = this.$element.text(); 92 | } 93 | this.calculateFontSize(); 94 | 95 | if (this.options.truncate) this.truncate(); 96 | 97 | return { 98 | $element: this.$element, 99 | size: this.fontSize 100 | }; 101 | }; 102 | 103 | Quickfit.prototype.calculateFontSize = function () { 104 | var letter, textWidth, i; 105 | 106 | textWidth = 0; 107 | for (i = 0; i < this.text.length; ++i) { 108 | letter = this.text.charAt(i); 109 | textWidth += this.quickfitHelper.getMeassure(letter); 110 | } 111 | 112 | this.targetFontSize = parseInt(this.options.width / textWidth); 113 | return this.fontSize = Math.max(this.options.min, Math.min(this.options.max, this.targetFontSize)); 114 | }; 115 | 116 | Quickfit.prototype.truncate = function () { 117 | var index, lastLetter, letter, textToAdd, textWidth; 118 | 119 | if (this.fontSize > this.targetFontSize) { 120 | textToAdd = ''; 121 | textWidth = 3 * this.quickfitHelper.getMeassure('.') * this.fontSize; 122 | 123 | index = 0; 124 | while (textWidth < this.options.width && index < this.text.length) { 125 | letter = this.text[index++]; 126 | if (lastLetter) textToAdd += lastLetter; 127 | textWidth += this.fontSize * this.quickfitHelper.getMeassure(letter); 128 | lastLetter = letter; 129 | } 130 | 131 | if (textToAdd.length + 1 === this.text.length) { 132 | textToAdd = this.text; 133 | } else { 134 | textToAdd += '...'; 135 | } 136 | this.textWasTruncated = true; 137 | 138 | return this.$element.attr('data-quickfit', this.text).html(textToAdd); 139 | 140 | } else { 141 | if (this.previouslyTruncated) { 142 | return this.$element.html(this.text); 143 | } 144 | } 145 | }; 146 | 147 | return Quickfit; 148 | 149 | })(); 150 | 151 | return $.fn.quickfit = function (options) { 152 | var measurements = []; 153 | 154 | // Separate measurements from repaints 155 | // First calculate all measurements... 156 | var $elements = this.each(function () { 157 | var measurement = new Quickfit(this, options).fit(); 158 | measurements.push(measurement); 159 | return measurement.$element; 160 | }); 161 | 162 | // ... then apply the measurements. 163 | for (var i = 0; i < measurements.length; i++) { 164 | var measurement = measurements[i]; 165 | 166 | measurement.$element.css({ fontSize: measurement.size + 'px' }); 167 | } 168 | 169 | return $elements; 170 | }; 171 | 172 | })(jQuery, window); 173 | -------------------------------------------------------------------------------- /pyconkr/static/js/jquery.shuffle.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | $.fn.shuffle = function() { 3 | var allElems = this.get(), 4 | getRandom = function(max) { 5 | return Math.floor(Math.random() * max); 6 | }, 7 | shuffled = $.map(allElems, function(){ 8 | var random = getRandom(allElems.length), 9 | randEl = $(allElems[random]).clone(true)[0]; 10 | allElems.splice(random, 1); 11 | return randEl; 12 | }); 13 | 14 | this.each(function(i){ 15 | $(this).replaceWith($(shuffled[i])); 16 | }); 17 | 18 | return $(shuffled); 19 | }; 20 | })(jQuery); 21 | -------------------------------------------------------------------------------- /pyconkr/static/js/rgb-hsv.js: -------------------------------------------------------------------------------- 1 | function RgbToHsv(rgb) { 2 | var min = Math.min(rgb.r, rgb.g, rgb.b), 3 | max = Math.max(rgb.r, rgb.g, rgb.b), 4 | delta = max - min, 5 | h, s, v = max; 6 | 7 | v = Math.floor(max / 255 * 100); 8 | if (max == 0) return {h:0, s:0, v:0, a:rgb.a}; 9 | s = Math.floor(delta / max * 100); 10 | var deltadiv = delta == 0 ? 1 : delta; 11 | if( rgb.r == max ) h = (rgb.g - rgb.b) / deltadiv; 12 | else if(rgb.g == max) h = 2 + (rgb.b - rgb.r) / deltadiv; 13 | else h = 4 + (rgb.r - rgb.g) / deltadiv; 14 | h = Math.floor(h * 60); 15 | if( h < 0 ) h += 360; 16 | return { h: h, s:s, v:v, a:rgb.a } 17 | } 18 | 19 | function HsvToRgb(hsv) { 20 | h = hsv.h / 360; 21 | s = hsv.s / 100; 22 | v = hsv.v / 100; 23 | 24 | if (s == 0) 25 | { 26 | var val = Math.round(v * 255); 27 | return {r:val,g:val,b:val,a:hsv.a}; 28 | } 29 | hPos = h * 6; 30 | hPosBase = Math.floor(hPos); 31 | base1 = v * (1 - s); 32 | base2 = v * (1 - s * (hPos - hPosBase)); 33 | base3 = v * (1 - s * (1 - (hPos - hPosBase))); 34 | if (hPosBase == 0) {red = v; green = base3; blue = base1} 35 | else if (hPosBase == 1) {red = base2; green = v; blue = base1} 36 | else if (hPosBase == 2) {red = base1; green = v; blue = base3} 37 | else if (hPosBase == 3) {red = base1; green = base2; blue = v} 38 | else if (hPosBase == 4) {red = base3; green = base1; blue = v} 39 | else {red = v; green = base1; blue = base2}; 40 | 41 | red = Math.round(red * 255); 42 | green = Math.round(green * 255); 43 | blue = Math.round(blue * 255); 44 | return {r:red,g:green,b:blue,a:hsv.a}; 45 | } 46 | 47 | function mixRgb(color1, color2, amount) 48 | { 49 | var hsv1 = RgbToHsv(color1); 50 | var hsv2 = RgbToHsv(color2); 51 | 52 | var h = amount * hsv2.h + (1.0 - amount) * hsv1.h; 53 | var s = amount * hsv2.s + (1.0 - amount) * hsv1.s; 54 | var v = amount * hsv2.v + (1.0 - amount) * hsv1.v; 55 | var a = amount * hsv2.a + (1.0 - amount) * hsv1.a; 56 | 57 | return HsvToRgb({h:h, s:s, v:v, a:a}); 58 | } 59 | 60 | function getSkyColorAt(hour, minute) 61 | { 62 | var skyCode = [ 63 | [{r: 38, g: 37, b: 51, a: 0.9}, {r: 0, g: 0, b: 0, a: 1.0}], 64 | [{r: 0, g: 0, b: 0, a: 0.5}, {r: 0, g: 0, b: 0, a: 0.9}], 65 | [{r: 75, g: 83, b: 92, a: 1.0}, {r:131, g:177, b:224, a: 1.0}], 66 | [{r:130, g:175, b:224, a: 1.0}, {r: 60, g:203, b:226, a: 1.0}], 67 | [{r:112, g:216, b:239, a: 1.0}, {r:198, g:180, b:220, a: 1.0}], 68 | [{r:112, g:163, b:239, a: 1.0}, {r:202, g:142, b:198, a: 1.0}], 69 | [{r: 88, g: 81, b:197, a: 1.0}, {r:230, g:105, b:145, a: 1.0}], 70 | [{r: 43, g: 28, b: 58, a: 1.0}, {r: 84, g: 18, b: 39, a: 1.0}] 71 | ]; 72 | 73 | var begin = Math.floor(hour/3); 74 | var end = (begin + 1) % 8; 75 | var mix = (hour - begin * 3) * 0.33 + (minute / 60.0 / 3.0); 76 | 77 | var color = skyCode[begin][0]; 78 | var from = mixRgb(skyCode[begin][0], skyCode[end][0], mix); 79 | var to = mixRgb(skyCode[begin][1], skyCode[end][1], mix); 80 | 81 | var css = "linear-gradient(to bottom, " 82 | + "rgba("+from.r+","+from.g+","+from.b+","+from.a+") 0%, " 83 | + "rgba("+to.r+","+to.g+","+to.b+","+to.a+") 100%)"; 84 | 85 | return css 86 | } 87 | -------------------------------------------------------------------------------- /pyconkr/static/js/teaser.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | var mapOptions = { 3 | center: new naver.maps.LatLng(37.5117731, 127.0592041), 4 | zoom: 10, 5 | zoomControl: true 6 | }; 7 | 8 | var map = new naver.maps.Map('map', mapOptions); 9 | 10 | var marker = new naver.maps.Marker({ 11 | position: new naver.maps.LatLng(37.5117731, 127.0592041), 12 | map: map 13 | }); 14 | 15 | var Slickconfig = { 16 | dots: true, 17 | prevArrow: false, 18 | nextArrow: false, 19 | autoplay: true, 20 | autoplaySpeed: 5000 21 | }; 22 | 23 | $('.js_slick').slick(Slickconfig); 24 | }); -------------------------------------------------------------------------------- /pyconkr/static/js/young-coder.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | var url = document.location.toString(); 3 | if (url.match('#')) { 4 | $(".nav-tabs a[href='#" + url.split('#')[1] + "']").tab('show'); 5 | } 6 | 7 | // Change hash for page-reload 8 | $('.nav-tabs a').on('shown.bs.tab', function (e) { 9 | e.preventDefault(); 10 | history.pushState({}, '', this.href); 11 | }); 12 | }); -------------------------------------------------------------------------------- /pyconkr/templates/badge/all.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {% include "badge/twitter.html" %} 4 | 5 | 6 | {% include "badge/facebook.html" %} 7 | 8 | 9 | {% include "badge/googleplus.html" %} 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /pyconkr/templates/badge/facebook.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /pyconkr/templates/badge/googleplus.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | -------------------------------------------------------------------------------- /pyconkr/templates/badge/twitter.html: -------------------------------------------------------------------------------- 1 | Tweet 2 | 3 | -------------------------------------------------------------------------------- /pyconkr/templates/banner.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /pyconkr/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% if LANGUAGE_CODE == 'en' %} 5 | 6 | {% else %} 7 | 8 | {% endif %} 9 | 10 | 11 | {% block head-title %}{% trans "PyCon Korea 2018" %}{% endblock %} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% block head-include %} 39 | {% endblock %} 40 | 41 | 42 | {% block nav %}{% include "nav.html" %}{% endblock %} 43 | {% if index %} 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

DIVE INTO
DIVERSITY

62 |

{% trans "PyCon Korea 2018" %}

63 |

64 | {% trans "Sprint" %} 2018.08.15({% trans "Wed" %}), 17({% trans "Fri" %}) 65 | {% trans "Tutorial" %} 2018.08.17({% trans "Fri" %}) 66 | {% trans "Conference" %} 2018.08.18 - 19({% trans "Sat" %}-{% trans "Sun" %}) 67 |

68 |

{% trans "Coex, Seoul" %}

69 |
70 |
71 |
72 | {% endif %} 73 | 74 |
75 |
76 | {% if not index %} 77 |

{% block title %}{{ title }}{% endblock %}

78 | {% endif %} 79 | {{ base_content | safe }} 80 | {% block content %}{% endblock %} 81 |
82 | 83 | {% block sponsors %} 84 |
85 |
86 |

{% trans "Sponsors" %}

87 | {% include "sponsors.html" %} 88 |
89 |
90 | {% endblock %} 91 |
92 | 93 | {% block unboxed_content %} {# for index ^^ #} 94 | {% endblock %} 95 | 96 | 97 | {% include "footer.html" %} 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /pyconkr/templates/child_care.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% load thumbnail %} 5 | 6 | 7 | -------------------------------------------------------------------------------- /pyconkr/templates/dev-robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /pyconkr/templates/disqus.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{% trans "Comments" %}

3 |
4 | 12 | 13 | blog comments powered by Disqus 14 | -------------------------------------------------------------------------------- /pyconkr/templates/facebook_script.html: -------------------------------------------------------------------------------- 1 |
2 | 9 | -------------------------------------------------------------------------------- /pyconkr/templates/flatpages/default.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block og-title %}{{ block.super }} {{ flatpage.title }}{% endblock %} 4 | {% block og-desc %}{{ flatpage.content|striptags|truncatechars:300 }}{% endblock %} 5 | {% block head-title %}{{ block.super }} {{ flatpage.title }}{% endblock %} 6 | {% block title %}{{ flatpage.title }}{% endblock %} 7 | -------------------------------------------------------------------------------- /pyconkr/templates/footer.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% load i18n %} 3 | 4 | 32 | 33 | -------------------------------------------------------------------------------- /pyconkr/templates/ga.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /pyconkr/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% load staticfiles %} 4 | 5 | 6 | {% block head-include %} 7 | 8 | 9 | 10 | {% endblock %} 11 | 12 | {% block content_wrapper %} 13 | {% endblock %} 14 | 15 | {% block content %} 16 | 17 | {% if recent_announcements %} 18 |
19 |
20 | {% for announcement in recent_announcements %} 21 |
22 |
23 |
{{ announcement }}
24 |
25 | {{ announcement.desc|safe }} 26 |
27 | 자세히 보기 28 |
29 |
30 | {% endfor %} 31 |
32 |
33 | {% endif %} 34 | 35 |
36 |

행사 상세

37 |

38 | 파이콘 한국은 한국의 파이썬 개발자들이 지식을 공유하고 만남을 갖기 위한 장입니다.

39 | 40 |

스프린트 (8/15, 8/17)

41 | 관심있는 오픈소스 프로젝트를 같은 장소에 모여 집중적으로 개발하는 자리입니다
42 | 스프린트 참가하기

43 | 44 |

튜토리얼 (8/17)

45 | 초보자들을 위해, 또는 새로운 것을 접하는 사람들을 위해 진행하는 교육 프로그램입니다.
46 | 튜토리얼 참가하기

47 | 48 |

컨퍼런스 (8/18 - 8/19)

49 | 파이썬 사용 사례, 지식 공유를 위한 행사입니다.
컨퍼런스의 자세한 시간표는 프로그램 > 세부일정 에서 확인하실 수 있습니다.

50 | 컨퍼런스 티켓 구매하기

51 | 52 | 이 외의 모든 공지사항은 공식 페이스북 과 이곳을 통해 공지될 예정입니다. 53 |

54 |
55 | 56 |
57 |

슬로건

58 |

"Dive into Diversity - 다양성에 빠지다"

59 |

60 | 파이콘 한국 2018은 "Dive into Diversity 다양성에 빠지다" 라는 슬로건으로 진행됩니다.

61 | 파이썬 커뮤니티는 다양한 기술, 개성 및 경험을 갖추고 있는 전세계 구성원들이 서로의 차이를 존중하고, 62 | 다른 견해에 귀를 기울이며, 올바른 상호작용을 통해 성장하는 커뮤니티를 지향해왔습니다.

63 | 파이콘 한국 2018에서는 다양한 사람들이 다양한 상황과 분야에서 다양한 의도를 가지고 파이썬과 만났던 사례를 공유합니다. 64 | 또한 우리가 원하는 것을 이루고 문제를 해결하는 도구로서, 파이썬이 어떻게 쓰이고 있는지 조명하려고 합니다. 65 | 파이콘 한국 2018을 통해 서로 다른 견해와 경험을 접하며, 생각의 경계를 허물고 새로운 아이디어를 발견하는 계기가 되었으면 합니다. 66 |

67 |
68 | 69 |
70 |

장소

71 |

서울 코엑스 그랜드볼룸

72 |
73 |
74 |
75 |
76 |
77 | 78 |
79 |

문의&공식계정

80 |

파이콘 한국 2018에 대한 모든 문의는 아래의 공식 연락처로 주시기 바랍니다.

81 |

이메일 support@pycon.kr

82 |

페이스북 https://www.facebook.com/pyconkorea/

83 |

스폰서 sponsor@pycon.kr

84 |
85 | {% endblock %} -------------------------------------------------------------------------------- /pyconkr/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load socialaccount %} 3 | {% load i18n %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block content %} 7 |

{% trans "Login via mail" %}

8 | 11 | {% crispy form %} 12 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /pyconkr/templates/login_mailsent.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |

{% trans "One-time login token url was sent to your mail. Please check your mailbox." %}

6 |

{% trans "Login token valid for only 1 hour." %} {% trans "If you lost token mail or be lated, please login again." %}

7 | {% trans "Back to home" %} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /pyconkr/templates/login_notvalidtoken.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |

{% trans "Requested token is not found or invalid." %}

6 |

{% trans "If you lost token mail or be lated, please login again." %}

7 | {% trans "Login" %} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /pyconkr/templates/mail/ticket_registered_html.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{% trans "PyCon Korea Registration confirmation" %}

3 |

PyCon Korea 2015 참가신청이 완료 되었습니다.

4 |

안녕하세요 {{payment_info.name}}님

5 |

6 | 본 메일은 PyCon Korea 2015 등록완료 확인 메일입니다.
7 |
8 | PyCon Korea 2015에 등록해주셔 감사합니다.
9 | PyCon Korea 2015 는 8월 29~30일 서울시 상암동 누리꿈 스퀘어에서 개최됩니다.
10 |

16 | 행사와 관련된 정보는 http://www.pycon.kr/2015/ 에서 확인하실 수 있습니다.
17 |
18 |

19 |

{% trans '결제 정보' %}

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
이메일{{payment_info.email}}
이름{{payment_info.name}}
상의 사이즈{{payment_info.top_size}}
전화번호{{payment_info.phone_number}}
소속{{payment_info.company}}
금액{{amount}}원 ({{payment_info.payment_method}})
거래번호{{payment_info.merchant_uid}}
등록완료일{{payment_info.modified}}
46 |

결제와 관련된 정보는 http://www.pycon.kr{% url 'registration_status' %} 에서도 확인이 가능합니다. 47 |

48 | PyCon Korea 2015 에서 뵙겠습니다.
49 |

50 | -------------------------------------------------------------------------------- /pyconkr/templates/mail/ticket_registered_text.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% trans "PyCon Korea Registration confirmation" %} 3 | 4 | PyCon Korea 2015 참가신청이 완료 되었습니다. 5 | 6 | 안녕하세요 {{payment_info.name}}님 7 | 8 | 본 메일은 PyCon Korea 2015 등록완료 확인 메일입니다. 9 | 10 | PyCon Korea 2015에 등록해주셔 감사합니다. 11 | PyCon Korea 2015 는 8월 29~30일 서울시 상암동 누리꿈 스퀘어에서 개최됩니다. 12 | 13 | - 장소 : 누리꿈 스퀘어 14 | - 주소 : 서울특별시 마포구 상암동 1605 15 | - 도로명 주소 : 서울특별시 마포구 월드컵북로 396 16 | - 안내 : http://nuri.nipa.kr/rt/ 17 | 18 | 행사와 관련된 정보는 http://www.pycon.kr/2015/ 에서 확인하실 수 있습니다. 19 | 20 | 결제 정보 21 | 22 | 이메일 : {{payment_info.email}} 23 | 이름 : {{payment_info.name}} 24 | 상의 사이즈 : {{payment_info.top_size}} 25 | 전화번호 : {{payment_info.phone_number}} 26 | 소속 : {{payment_info.company}} 27 | 거래번호 : {{payment_info.merchant_uid}} 28 | 금액 : {{amount}}원 ({{payment_info.payment_method}}) 29 | 등록완료일 : {{payment_info.modified}} 30 | 31 | 32 | 결제와 관련된 정보는 http://www.pycon.kr{% url 'registration_status' %} 에서도 확인이 가능합니다. 33 | 34 | PyCon Korea 2015 에서 뵙겠습니다. -------------------------------------------------------------------------------- /pyconkr/templates/mail/token_html.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{% trans "PyCon Korea 2018" %}

3 |

{% trans "You can login to PyCon Korea 2018 homepage via below url." %}

4 |

{% trans "Link" %}: 5 | 6 | http://{{ request.get_host }}{% url "login_req" token.token %} 7 | 8 |

9 | -------------------------------------------------------------------------------- /pyconkr/templates/mail/token_text.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% trans "You can login to PyCon Korea 2018 homepage via below url." %} 3 | http://{{ request.get_host }}{% url "login_req" token.token %} 4 | -------------------------------------------------------------------------------- /pyconkr/templates/nav.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% load i18n %} 3 | 88 | 89 | {##} 103 | 104 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/announcement_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block og-title %}{{ block.super }} {{ object.title }}{% endblock %} 5 | {% block og-desc %}{{ object.desc|striptags|truncatechars:300 }}{% endblock %} 6 | {% block head-title %}{{ object.title }}{% endblock %} 7 | 8 | {% block content %} 9 | {{ object.desc|safe }} 10 |

{{ object.at }}

11 |
12 | 13 | {% trans "Back to list" %} 14 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/announcement_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 | {% if not object_list %} 6 |

{% trans "Ready for content" %}

7 | {% endif %} 8 | 9 | {% for announcement in object_list %} 10 |
11 |
12 |

13 | {{ announcement }} 14 | {{ announcement.at|date:"Y-m-d" }} 15 |

16 |
17 |
18 | {{ announcement.desc|striptags|truncatechars:300|safe }} 19 | 20 | {% trans "Read more" %} 21 | 22 |
23 |
24 | {% endfor %} 25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/jobfair_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 | {% for obj in object_list %} 6 |
7 |
8 |
9 | sponsor image 10 |
11 |

{{ obj.name }}

12 | {{ obj.location }} 13 |
14 |
15 |
16 |
17 |
18 | {{ obj.desc|safe }} 19 |
20 |
21 | {% endfor %} 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/patron_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load thumbnail %} 4 | {% load i18n %} 5 | 6 | {% block content %} 7 |
8 |

파이콘 한국 2018 을 후원해주신 개인 후원자 분들의 명단입니다. 후원해주셔서 감사합니다.

9 |
10 |
    11 | {% for obj in object_list %} 12 | {% with obj_name=obj.user.profile.name|default:obj.name %} 13 |
  • 14 |
    15 | {% thumbnail obj.user.profile.image "128x128" crop="center" as im %} 16 | photo of {{ obj_name }} 17 | {% empty %} 18 | 19 | {% endthumbnail %} 20 |
    21 |
    22 |

    23 | {{ obj_name }} 24 | {% if obj.user.profile.organization %} 25 | / {{ obj.user.profile.organization }} 26 | {% elif obj.company %} 27 | / {{ obj.company }} 28 | {% endif %} 29 |

    30 | {% if obj.user.profile.bio %} 31 |
    32 | {{ obj.user.profile.bio|safe }} 33 |
    34 | {% endif %} 35 |
    36 |
  • 37 | {% endwith %} 38 | {% endfor %} 39 |
40 |
41 |
42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/profile_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load crispy_forms_tags %} 4 | 5 | {% block title %}{% trans "Profile" %}{% endblock %} 6 | 7 | {% block content %} 8 | {% crispy form %} 9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/program_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block head-title %}{{ block.super }} {% trans "Program" %} | {{ program.name }}{% endblock %} 5 | {% block og-title %}{{ program.name }}{% endblock %} 6 | {% block og-desc %}{{ program.desc|striptags|safe }}{% endblock %} 7 | {% block nav %}{% include "nav.html" with title=program.name %}{% endblock %} 8 | {% block title %}{{ program.name }}{% endblock %} 9 | 10 | {% block content %} 11 | {% include "badge/all.html" %} 12 | 60 | {% if program.get_slide_url_by_begin_time %} 61 |

{% trans "Slide" %}


62 | {{ program.get_slide_url_by_begin_time|urlize }}
63 | {% endif %} 64 | {% if program.video_url %} 65 |

{% trans "Video" %}


66 | {{ program.video_url|urlize }}
67 | {% endif %} 68 | {% if program.pdf_url %} 69 |

{% trans "PDF" %}


70 | {{ program.pdf_url|urlize }}
71 | {% endif %} 72 | {% if program.desc %} 73 |

{% trans "Description" %}


74 | {{ program.desc|safe }}
75 | {% endif %} 76 | {% if editable %} 77 |
78 | {% trans "Edit" %} 79 | {% endif %} 80 | {% include "disqus.html" %} 81 | {% endblock %} 82 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/program_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load crispy_forms_tags %} 3 | 4 | {% block head-include %} 5 | {{ form.media }} 6 | {% endblock %} 7 | 8 | {% block head-title %}{{ program }}{% endblock %} 9 | {% block title %}{{ program }}{% endblock %} 10 | 11 | {% block content %} 12 | {% crispy form %} 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/program_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 | {% if not object_list %} 6 |

{% trans "Ready for content" %}

7 | {% endif %} 8 | 9 | {% for obj in object_list %} 10 | 11 |

12 | {{ obj.name }} 13 |

14 |
15 | 31 | {% endfor %} 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/program_preference.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |
6 | 14 | {% csrf_token %} 15 | 16 |
17 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/proposal_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load thumbnail %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block content %} 7 |
8 | {% if request.user.proposal %} 9 |

10 | {{ proposal.title }} 11 | 12 |

13 |

14 | {{ proposal.get_difficulty_display }} 15 | {{ proposal.get_duration_display }} 16 | {{ proposal.get_language_display }} 17 |

18 |
{{ proposal.brief|linebreaks }}
19 |
20 |
21 |

{% trans "Detailed description" %}

22 | {{ proposal.desc|safe }} 23 |
24 |
25 |
26 |

{% trans "Comment to reviewers" %}

27 | {{ proposal.comment|safe }} 28 |
29 | 30 | {% endif %} 31 |
32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/proposal_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load crispy_forms_tags i18n %} 3 | 4 | {% block head-include %} 5 | {{ form.media }} 6 | {% endblock %} 7 | 8 | {% block content %} 9 | 10 | {% crispy form %} 11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/room_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block head-title %}{{ object.name }}{% endblock %} 4 | 5 | {% block content %} 6 | {{ object }} 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/speaker_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block head-title %}{{ block.super }} {% trans "Speaker" %} | {{ speaker.name }}{% endblock %} 5 | {% block og-title %}{{ speaker.name }}{% endblock %} 6 | {% block og-image %}{{ speaker.get_image_url }}{% endblock %} 7 | {% block og-desc %}{{ speaker.desc|striptags }}{% endblock %} 8 | {% block nav %}{% include "nav.html" with title=speaker.name %}{% endblock %} 9 | {% block title %}{{ speaker.name }}{% endblock %} 10 | 11 | {% block content %} 12 | {% include "badge/all.html" %} 13 |
14 | photo of {{ speaker.slug }} 15 | {{ speaker.get_badges|safe }} 16 | {% if speaker.desc %} 17 |

{% trans "Profile" %}

18 |
19 | {{ speaker.desc|safe }} 20 |
21 | {% endif %} 22 |

{% trans "Program" %}

23 | 28 |
29 | {% if editable %} 30 |
31 | {% trans "Edit" %} 32 | {% endif %} 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/speaker_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load crispy_forms_tags %} 3 | 4 | {% block head-include %} 5 | {{ form.media }} 6 | {% endblock %} 7 | 8 | {% block head-title %}{{ speaker }}{% endblock %} 9 | {% block title %}{{ speaker }}{% endblock %} 10 | 11 | {% block content %} 12 | {% crispy form %} 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/speaker_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% load thumbnail %} 5 | 6 | {% block content %} 7 | 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/sponsor_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block head-title %}{{ block.super }} {% trans "Sponsor" %} | {{ sponsor.name }}{% endblock %} 5 | {% block og-title %}{{ block.super }} {% trans "Sponsor" %} | {{ sponsor.name }}{% endblock %} 6 | {% block og-image %}{{ sponsor.image.url }}{% endblock %} 7 | {% block nav %}{% include "nav.html" with title=sponsor.name %}{% endblock %} 8 | {% block title %}{{ sponsor.name }}{% endblock %} 9 | 10 | {% block content %} 11 | 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/sponsor_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans "Sponsors" %}{% endblock %} 5 | {% block content %} 6 |
7 |
8 | {% include "sponsors.html" with detail="True" %} 9 |
10 |
11 | {% endblock %} 12 | {% block sponsors %} 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/sprintproposal_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load thumbnail %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block head-title %}{{ sprint.title }} — {{ block.super }}{% endblock %} 7 | {% block og-title %}{{ sprint.title }}{% endblock %} 8 | {% block og-desc %}{{ sprint.project_brief }}{% endblock %} 9 | 10 | {% block title %} 11 |

12 | {{ sprint.title }} 13 | {% if sprint.user == request.user %} 14 | 15 | {% trans "Edit" %} 16 | 17 | {% endif %} 18 |

19 | {% endblock %} 20 | {% block content %} 21 |
22 |

{% trans "Sprinter" %}

23 |

24 | {{ sprint.user.profile.name }} 25 | {% if sprint.user.profile.organization %} 26 | {{ sprint.user.profile.organization }} 27 | {% endif %} 28 |

29 |
30 | {{ sprint.user.profile.bio|safe }} 31 |
32 |
33 |
34 |

{% trans "Tutorial Information" %}

35 | {{ sprint.comment|safe }} 36 |
37 |
38 |
39 |

{% trans "Sprint Language" %}

40 |
{{ sprint.language|linebreaks }}
41 |

{% trans "Project brief" %}

42 |
{{ sprint.project_brief|urlize|linebreaks }}
43 |

{% trans "Detailed description" %}

44 |
{{ sprint.contribution_desc|safe }}
45 |
46 |
47 |
48 |
49 |

{% trans "Project URL" %}

50 |
{{ sprint.project_url|urlize|linebreaks }}
51 |
52 |
53 |
54 |
55 | 56 | 57 | {% trans "Back to list" %} 58 | 59 | {% if joined %} 60 | 61 | {% trans "Leave this event" %} 62 | 63 | {% else %} 64 | 65 | {% trans "Join this event" %} 66 | 67 | {% endif %} 68 |
69 | 70 |

{% trans "Attendees" %}

71 | {% if not attendees %} 72 |

{% trans "No attendees, yet." %}

73 | {% else %} 74 | 92 |
93 | {% endif %} 94 | {% endblock %} 95 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/sprintproposal_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |

Sprints

6 | 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/tutorialproposal_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load thumbnail %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block head-title %}{{ tutorial.title }} — {{ block.super }}{% endblock %} 7 | {% block og-title %}{{ tutorial.title }}{% endblock %} 8 | {% block og-desc %}{{ tutorial.brief }}{% endblock %} 9 | 10 | {% block title %} 11 |

12 | {{ tutorial.title }} 13 | {% if tutorial.user == request.user %} 14 | 15 | {% trans "Edit" %} 16 | 17 | {% endif %} 18 |

19 | {% endblock %} 20 | {% block content %} 21 |
22 |

23 | {{ tutorial.get_type_display }} 24 | {{ tutorial.get_difficulty_display }} 25 | {{ tutorial.get_duration_display }} 26 | {{ tutorial.get_language_display }} 27 | {{ tutorial.capacity }} 명 28 |

29 |

30 | {{ tutorial.user.profile.name }} 31 | {% if tutorial.user.profile.organization %} 32 | {{ tutorial.user.profile.organization }} 33 | {% endif %} 34 |

35 |
36 | {{ tutorial.user.profile.bio|safe }} 37 |
38 |
39 | 40 | {% if option %} 41 | {% if is_registered %} 42 | 43 | 이미 등록하셨습니다. 44 | 45 | {% elif option.is_sold_out %} 46 | 47 | 등록 마감 48 | 49 | {% else %} 50 | 51 | 참가신청하기 52 | 53 | {% endif %} 54 | {% endif %} 55 | 56 |
57 |

{% trans "Tutorial Information" %}


58 | 일시 : {{ tutorial.begin_at|date:'Y-m-d H:i:s' }} ~ {{ tutorial.end_at|date:'Y-m-d H:i:s' }} 59 | {{ tutorial.comment|safe }} 60 |
61 |
62 |
63 |

{% trans "Brief" %}

64 |
{{ tutorial.brief|linebreaks }}
65 |
66 |
67 |
68 |

{% trans "Detailed description" %}

69 | {{ tutorial.desc|safe }} 70 |
71 |
72 |
73 | 74 | {% trans "Back to list" %} 75 | 76 | 77 |
78 | {% endblock %} 79 | -------------------------------------------------------------------------------- /pyconkr/templates/pyconkr/tutorialproposal_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |

Tutorials

6 | 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /pyconkr/templates/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /media/speaker/*.jpg$ 3 | -------------------------------------------------------------------------------- /pyconkr/templates/sponsors.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | {% for lvl in levels %} 4 |

{{ lvl.name }}

5 | 21 | {% empty %} 22 |

{% trans "Ready for content" %}

23 | {% endfor %} 24 |
25 | -------------------------------------------------------------------------------- /pyconkr/templates/submenu.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /pyconkr/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from django.test import TestCase 4 | from django.http import HttpResponse 5 | from django.test import Client 6 | from django.core.urlresolvers import reverse_lazy, reverse 7 | from django.contrib.auth import get_user_model 8 | from django_dynamic_fixture import G 9 | 10 | from pyconkr.models import TutorialCheckin, TutorialProposal 11 | from pyconkr.helper import render_io_error 12 | from registration.models import Registration 13 | 14 | User = get_user_model() 15 | 16 | 17 | class HelperFunctionTestCase(TestCase): 18 | def setUp(self): 19 | pass 20 | 21 | def tearDown(self): 22 | pass 23 | 24 | def test_render_io_error(self): 25 | a = render_io_error("test reason") 26 | self.assertEqual(a.status_code, 406, "render io error status code must be 406") 27 | 28 | 29 | class PaymentTestCase(TestCase): 30 | def setUp(self): 31 | self.client = Client() 32 | self.user = User.objects.create_user('testname', 'test@test.com', 'testpassword') 33 | self.client.login(username='testname', password='testpassword') 34 | 35 | def tearDown(self): 36 | pass 37 | 38 | def test_view_registration_payment(self): 39 | url = reverse('registration_payment') 40 | response = self.client.post(url, {'test': 1}) 41 | self.assertEqual(response['content-type'], 'application/json', 'Result has to be JSON') 42 | 43 | 44 | class ProfileTest(TestCase): 45 | def test_profile_is_created_when_user_save(self): 46 | user = User.objects.create_user('test', 'test@email.com', 'password') 47 | self.assertNotEqual(user.profile, None) 48 | 49 | def test_redirect_to_profile_edit_page_when_user_has_not_profile(self): 50 | User.objects.create_user('test', 'test@email.com', 'password') 51 | client = Client() 52 | client.login(username='test', password='password') 53 | response = client.get(reverse('profile')) 54 | self.assertEqual(response.status_code, 302) 55 | self.assertEqual(response['location'], reverse('profile_edit')) 56 | 57 | 58 | class ProposeTest(TestCase): 59 | def test_redirect_to_profile_when_propose_without_profile(self): 60 | user = User.objects.create_user('test', 'test@email.com', 'password') 61 | client = Client() 62 | client.login(username='test', password='password') 63 | response = client.get(reverse('propose')) 64 | self.assertEqual(response.status_code, 302) 65 | self.assertEqual(response['location'], reverse('profile_edit')) 66 | 67 | class TutorialTest(TestCase): 68 | def test_tutorial_detail_attendees(self): 69 | # set capacity for test waiting flag 70 | tutorial = G(TutorialProposal, capacity='S') 71 | first_user = G(User, email='first@email.com') 72 | second_user = G(User, email='second@email.com') 73 | G(Registration, user=second_user, payment_status='paid') 74 | many_users = [G(User, email=str(x)+'@email.com') for x in range(9)] 75 | first_checkin = G(TutorialCheckin, tutorial=tutorial, user=first_user) 76 | second_checkin = G(TutorialCheckin, tutorial=tutorial, user=second_user) 77 | many_checkins = [G(TutorialCheckin, tutorial=tutorial, user=x) for x in 78 | many_users] 79 | response = self.client.get(reverse('tutorial', kwargs={'pk': tutorial.pk})) 80 | attendees = response.context['attendees'] 81 | self.assertEqual(len(attendees), 11) 82 | # user email head? 83 | self.assertEqual(attendees[0]['name'], 'first') 84 | self.assertEqual(attendees[0]['registered'], False) 85 | self.assertEqual(attendees[1]['registered'], True) 86 | # waiting order by pk 87 | self.assertEqual(attendees[0]['waiting'], False) 88 | self.assertEqual(attendees[10]['waiting'], True) 89 | -------------------------------------------------------------------------------- /pyconkr/translation.py: -------------------------------------------------------------------------------- 1 | from modeltranslation.translator import translator, TranslationOptions 2 | from django.contrib.flatpages.models import FlatPage 3 | from .models import ( 4 | Room, 5 | ProgramCategory, ProgramTime, 6 | Sponsor, SponsorLevel, 7 | Speaker, Program, 8 | Announcement, Banner 9 | ) 10 | 11 | 12 | class FlatPageTranslationOptions(TranslationOptions): 13 | fields = ('title', 'content',) 14 | translator.register(FlatPage, FlatPageTranslationOptions) 15 | 16 | 17 | class RoomTranslationOptions(TranslationOptions): 18 | fields = ('name', 'desc',) 19 | translator.register(Room, RoomTranslationOptions) 20 | 21 | 22 | class ProgramCategoryTranslationOptions(TranslationOptions): 23 | fields = ('name',) 24 | translator.register(ProgramCategory, ProgramCategoryTranslationOptions) 25 | 26 | 27 | class ProgramTimeTranslationOptions(TranslationOptions): 28 | fields = ('name',) 29 | translator.register(ProgramTime, ProgramTimeTranslationOptions) 30 | 31 | 32 | class SponsorTranslationOptions(TranslationOptions): 33 | fields = ('name', 'desc',) 34 | translator.register(Sponsor, SponsorTranslationOptions) 35 | 36 | 37 | class SponsorLevelTranslationOptions(TranslationOptions): 38 | fields = ('name', 'desc',) 39 | translator.register(SponsorLevel, SponsorLevelTranslationOptions) 40 | 41 | 42 | class SpeakerTranslationOptions(TranslationOptions): 43 | fields = ('name', 'desc',) 44 | translator.register(Speaker, SpeakerTranslationOptions) 45 | 46 | 47 | class ProgramTranslationOptions(TranslationOptions): 48 | fields = ('name', 'desc',) 49 | translator.register(Program, ProgramTranslationOptions) 50 | 51 | 52 | class AnnouncementTranslationOptions(TranslationOptions): 53 | fields = ('title', 'desc',) 54 | translator.register(Announcement, AnnouncementTranslationOptions) 55 | 56 | 57 | class BannerTranslationOptions(TranslationOptions): 58 | fields = ('desc',) 59 | translator.register(Banner, BannerTranslationOptions) 60 | -------------------------------------------------------------------------------- /pyconkr/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls import include, url 3 | from django.conf.urls.i18n import i18n_patterns 4 | from django.conf.urls.static import static 5 | from django.contrib.flatpages import views 6 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 7 | from django.contrib.auth.decorators import login_required 8 | from django.views.generic.base import TemplateView 9 | from pyconkr.views import TutorialProposalCreate, TutorialProposalDetail, \ 10 | TutorialProposalUpdate, TutorialProposalList, SprintProposalList, tutorial_join,\ 11 | SprintProposalCreate, SprintProposalDetail, sprint_join, SprintProposalUpdate 12 | 13 | from .views import index, schedule, robots, youngcoder, child_care 14 | from .views import RoomDetail 15 | from .views import AnnouncementList, AnnouncementDetail 16 | from .views import SpeakerList, SpeakerDetail, SpeakerUpdate 17 | from .views import SponsorList, SponsorDetail, PatronList 18 | from .views import ProgramList, ProgramDetail, ProgramUpdate, PreferenceList 19 | from .views import ProposalCreate, ProposalUpdate, ProposalDetail 20 | from .views import ProfileDetail, ProfileUpdate 21 | from .views import login, login_req, login_mailsent, logout 22 | 23 | from django.contrib import admin 24 | admin.autodiscover() 25 | 26 | urlpatterns = [ 27 | url(r'^robots.txt$', robots, name='robots'), 28 | url(r'^summernote/', include('django_summernote.urls')), 29 | url(r'^admin/', include(admin.site.urls)), 30 | 31 | url(r'^accounts/', include('allauth.urls')), 32 | url(r'^i18n/', include('django.conf.urls.i18n')), 33 | ] 34 | 35 | urlpatterns += i18n_patterns( 36 | url(r'^$', index, name='index'), 37 | url(r'^room/(?P\d+)$', 38 | RoomDetail.as_view(), name='room'), 39 | 40 | url(r'^about/announcements/$', 41 | AnnouncementList.as_view(), name='announcements'), 42 | url(r'^about/announcement/(?P\d+)$', 43 | AnnouncementDetail.as_view(), name='announcement'), 44 | url(r'^about/sponsor/$', 45 | SponsorList.as_view(), name='sponsors'), 46 | url(r'^about/patron/$', 47 | PatronList.as_view(), name='patrons'), 48 | url(r'^about/sponsor/(?P[\w|-]+)$', 49 | SponsorDetail.as_view(), name='sponsor'), 50 | 51 | url(r'^programs?/list/$', 52 | ProgramList.as_view(), name='programs'), 53 | url(r'^programs?/preference/$', 54 | login_required(PreferenceList.as_view()), name='program_preference'), 55 | url(r'^program/(?P\d+)$', 56 | ProgramDetail.as_view(), name='program'), 57 | url(r'^program/(?P\d+)/edit$', 58 | ProgramUpdate.as_view(), name='program_edit'), 59 | url(r'^programs?/speakers?/$', 60 | SpeakerList.as_view(), name='speakers'), 61 | url(r'^programs?/speakers?/(?P\w+)$', 62 | SpeakerDetail.as_view(), name='speaker'), 63 | url(r'^programs?/speakers?/(?P\w+)/edit$', 64 | SpeakerUpdate.as_view(), name='speaker_edit'), 65 | url(r'^programs?/schedule/$', 66 | schedule, name='schedule'), 67 | url(r'^programs?/youngcoder/$', 68 | youngcoder, name='youngcoder'), 69 | url(r'^programs?/child_care/$', 70 | child_care, name='child_care'), 71 | url(r'^programs?/tutorial/$', 72 | TutorialProposalList.as_view(), name='tutorial'), 73 | url(r'^programs?/sprint/$', 74 | SprintProposalList.as_view(), name='sprint'), 75 | url(r'^programs?/tutorial/(?P\d+)$', 76 | TutorialProposalDetail.as_view(), name='tutorial'), 77 | url(r'^programs?/tutorial/(?P\d+)/join/$', 78 | login_required(tutorial_join), name='tutorial-join'), 79 | url(r'^programs?/sprint/(?P\d+)$', 80 | SprintProposalDetail.as_view(), name='sprint'), 81 | url(r'^programs?/sprint/(?P\d+)/join/$', 82 | login_required(sprint_join), name='sprint-join'), 83 | 84 | url(r'^cfp/propose/$', 85 | login_required(ProposalCreate.as_view()), name='propose'), 86 | url(r'^cfp/tutorial-propose/$', 87 | login_required(TutorialProposalCreate.as_view()), name='tutorial-propose'), 88 | url(r'^profile/proposal/$', 89 | login_required(ProposalDetail.as_view()), name='proposal'), 90 | url(r'^cfp/sprint-propose/$', 91 | login_required(SprintProposalCreate.as_view()), name='sprint-propose'), 92 | 93 | url(r'^profile/proposal/edit$', 94 | login_required(ProposalUpdate.as_view()), name='proposal-update'), 95 | url(r'^profile/tutorial-proposal/edit$', 96 | login_required(TutorialProposalUpdate.as_view()), name='tutorial-proposal-update'), 97 | url(r'^profile/sprint-proposal/edit$', 98 | login_required(SprintProposalUpdate.as_view()), name='sprint-proposal-update'), 99 | url(r'^profile$', 100 | login_required(ProfileDetail.as_view()), name='profile'), 101 | url(r'^profile/edit$', 102 | login_required(ProfileUpdate.as_view()), name='profile_edit'), 103 | 104 | url(r'^login/$', login, name='login'), 105 | url(r'^login/req/(?P[a-z0-9\-]+)$', login_req, name='login_req'), 106 | url(r'^login/mailsent/$', login_mailsent, name='login_mailsent'), 107 | url(r'^logout/$', logout, name='logout'), 108 | 109 | url(r'^registration/', include('registration.urls')), 110 | 111 | # for rosetta 112 | url(r'^rosetta/', include('rosetta.urls')), 113 | 114 | # for flatpages 115 | url(r'^pages/', include('django.contrib.flatpages.urls')), 116 | url(r'^(?P.*/)$', views.flatpage, name='flatpage'), 117 | 118 | prefix_default_language=False 119 | ) 120 | 121 | # for development 122 | if settings.DEBUG: 123 | urlpatterns += staticfiles_urlpatterns() 124 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 125 | -------------------------------------------------------------------------------- /pyconkr/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for pyconkr project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pyconkr.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /registration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/registration/__init__.py -------------------------------------------------------------------------------- /registration/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class RegistrationConfig(AppConfig): 7 | name = 'registration' 8 | -------------------------------------------------------------------------------- /registration/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from crispy_forms.helper import FormHelper 3 | from crispy_forms.layout import Submit 4 | from django import forms 5 | from django.utils.translation import ugettext_lazy as _ 6 | 7 | from .models import Registration, ManualPayment 8 | 9 | 10 | class RegistrationForm(forms.ModelForm): 11 | base_price = forms.IntegerField(label=_('Base Price KRW')) 12 | 13 | def __init__(self, *args, **kwargs): 14 | super(RegistrationForm, self).__init__(*args, **kwargs) 15 | self.fields['email'].widget.attrs['readonly'] = True 16 | self.fields['base_price'].widget.attrs['readonly'] = True 17 | self.fields['option'].widget.attrs['disabled'] = True 18 | self.helper = FormHelper() 19 | self.helper.form_id = 'registration-form' 20 | self.helper.form_method = 'post' 21 | self.helper.add_input(Submit('submit', _('Submit'), disabled='disabled')) 22 | 23 | class Meta: 24 | model = Registration 25 | fields = ('email', 'option', 'base_price', 'name', 'top_size', 'company', 'phone_number', 'payment_method') 26 | labels = { 27 | 'name': _('Name'), 28 | 'option': _('Option'), 29 | 'top_size': _('Top Size'), 30 | 'email': _('E-Mail'), 31 | 'company': _('Company or Organization'), 32 | 'phone_number': _('Phone Number'), 33 | 'payment_method': _('Payment Method'), 34 | } 35 | 36 | 37 | class RegistrationFormWithoutTopSize(RegistrationForm): 38 | def __init__(self, *args, **kwargs): 39 | super(RegistrationFormWithoutTopSize, self).__init__(*args, **kwargs) 40 | self.fields.pop('top_size') 41 | 42 | 43 | class RegistrationAdditionalPriceForm(RegistrationForm): 44 | additional_price = forms.IntegerField(min_value=0) 45 | 46 | class Meta: 47 | model = Registration 48 | fields = ('email', 'option', 'base_price', 'additional_price', 'name', 'top_size', 'company', 'phone_number', 49 | 'payment_method') 50 | labels = { 51 | 'name': _('Name'), 52 | 'option': _('Option'), 53 | 'top_size': _('Top Size'), 54 | 'additional_price': _('Additional Funding KRW'), 55 | 'email': _('E-Mail'), 56 | 'company': _('Company or Organization'), 57 | 'phone_number': _('Phone Number'), 58 | 'payment_method': _('Payment Method') 59 | } 60 | 61 | 62 | class ManualPaymentForm(forms.ModelForm): 63 | email = forms.EmailField() 64 | base_price = forms.IntegerField(label=_('Base Price KRW')) 65 | 66 | def __init__(self, *args, **kwargs): 67 | super(ManualPaymentForm, self).__init__(*args, **kwargs) 68 | self.fields['title'].widget.attrs['readonly'] = True 69 | self.fields['email'].widget.attrs['readonly'] = True 70 | self.fields['base_price'].widget.attrs['readonly'] = True 71 | self.fields['payment_method'].widget.attrs['readonly'] = True 72 | self.helper = FormHelper() 73 | self.helper.form_id = 'manual-payment-form' 74 | self.helper.form_method = 'post' 75 | self.helper.add_input(Submit('submit', _('Submit'), disabled='disabled')) 76 | 77 | class Meta: 78 | model = ManualPayment 79 | fields = ('title', 'email', 'base_price', 'payment_method') 80 | labels = { 81 | 'title': _('Title'), 82 | 'email': _('Email'), 83 | 'payment_method': _('Payment Method'), 84 | } 85 | 86 | 87 | class IssueSubmitForm(forms.Form): 88 | user_id = forms.IntegerField() 89 | -------------------------------------------------------------------------------- /registration/iamporter/__init__.py: -------------------------------------------------------------------------------- 1 | from .iamporter import Iamporter, IamporterError, get_access_token 2 | -------------------------------------------------------------------------------- /registration/iamporter/iamporter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import requests 3 | import datetime 4 | 5 | 6 | class IamporterError(Exception): 7 | def __init__(self, code=None, message=None): 8 | self.code = code 9 | self.message = message 10 | return super(IamporterError, self).__init__('{code}: {message}'.format(code=code, message=message)) 11 | 12 | def get_access_token(api_key, api_secret): 13 | url = 'https://api.iamport.kr/users/getToken' 14 | response = requests.post(url, data=dict( 15 | imp_key=api_key, 16 | imp_secret=api_secret, 17 | )) 18 | 19 | if response.status_code != 200: 20 | raise IamporterError(response.status_code, response.content) 21 | 22 | # TODO : validate expire time 23 | result = response.json() 24 | 25 | if result['code'] is not 0: 26 | raise IamporterError(result['code'], result['message']) 27 | 28 | return result['response']['access_token'] 29 | 30 | 31 | class Iamporter(object): 32 | TOKEN_HEADER = 'X-ImpTokenHeader' 33 | 34 | def __init__(self, access_token): 35 | self._access_code = access_token 36 | 37 | def _set_default(self, data, headers): 38 | if not data: 39 | data = {} 40 | 41 | if not headers: 42 | headers = {} 43 | headers[self.TOKEN_HEADER] = self._access_code 44 | 45 | return data, headers 46 | 47 | def _parse_response(self, response): 48 | if response.status_code != 200 or not response.content: 49 | raise IamporterError(response.status_code, response.content) 50 | 51 | result = response.json() 52 | 53 | if result['code'] is not 0: 54 | raise IamporterError(result['code'], result['message']) 55 | 56 | return result['response'] 57 | 58 | def _get(self, url, data=None, headers=None): 59 | data, headers = self._set_default(data, headers) 60 | response = requests.get(url, headers=headers, params=data) 61 | 62 | return self._parse_response(response) 63 | 64 | def _post(self, url, data=None, headers=None): 65 | data, headers = self._set_default(data, headers) 66 | response = requests.post(url, headers=headers, data=data) 67 | 68 | return self._parse_response(response) 69 | 70 | def onetime(self, **params): 71 | url = 'https://api.iamport.kr/subscribe/payments/onetime/' 72 | keys = ['token', 'merchant_uid', 'amount', 'vat', 'card_number', 'expiry', 'birth', 'pwd_2digit', 73 | 'name', 'remember_me', 'buyer_name', 'buyer_email', ] 74 | data = {k: v for k, v in params.items() if k in keys} 75 | return self._post(url, data) 76 | 77 | def foreign(self, **params): 78 | url = 'https://api.iamport.kr/subscribe/payments/foreign/' 79 | keys = ['token', 'merchant_uid', 'amount', 'vat', 'card_number', 'expiry', 80 | 'name', 'buyer_name', 'buyer_email', ] 81 | data = {k: v for k, v in params.items() if k in keys} 82 | return self._post(url, data) 83 | 84 | def cancel(self, **params): 85 | url = 'https://api.iamport.kr/payments/cancel/' 86 | keys = ['merchant_uid', 'reason', ] 87 | data = {k: v for k, v in params.items() if k in keys} 88 | return self._post(url, data) 89 | 90 | def find_by_merchant_uid(self, merchant_uid): 91 | url = 'https://api.iamport.kr/payments/find/{merchant_uid}'.format(merchant_uid=merchant_uid) 92 | return self._get(url) 93 | 94 | def get_paid_list(self, since, until=datetime.datetime.now()): 95 | url = 'https://api.iamport.kr/payments/status/{payment_status}'.format(payment_status='paid') 96 | since = int(since.strftime('%s')) 97 | until = int(until.strftime('%s')) 98 | data = { 99 | 'from': since, 100 | 'to': until, 101 | 'page': 1, 102 | } 103 | full_list = [] 104 | while True: 105 | result = self._get(url, data) 106 | full_list.extend(result['list']) 107 | if result['next'] != 0: 108 | data['page'] += 1 109 | continue 110 | else: 111 | break 112 | return full_list 113 | -------------------------------------------------------------------------------- /registration/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-08-09 17:29+0900\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: registration/forms.py:11 registration/forms.py:64 21 | msgid "Base Price KRW" 22 | msgstr "" 23 | 24 | #: registration/forms.py:21 registration/forms.py:75 25 | msgid "Submit" 26 | msgstr "" 27 | 28 | #: registration/forms.py:27 registration/forms.py:51 29 | #: registration/templates/registration/status.html:16 30 | #: registration/templates/registration/status.html:90 31 | msgid "Name" 32 | msgstr "" 33 | 34 | #: registration/forms.py:28 registration/forms.py:52 35 | #: registration/templates/registration/status.html:49 36 | msgid "Option" 37 | msgstr "" 38 | 39 | #: registration/forms.py:29 registration/forms.py:53 40 | #: registration/templates/registration/status.html:27 41 | #: registration/templates/registration/status.html:32 42 | msgid "Top Size" 43 | msgstr "" 44 | 45 | #: registration/forms.py:30 registration/forms.py:55 46 | msgid "E-Mail" 47 | msgstr "" 48 | 49 | #: registration/forms.py:31 registration/forms.py:56 50 | #: registration/templates/registration/status.html:41 51 | msgid "Company or Organization" 52 | msgstr "" 53 | 54 | #: registration/forms.py:32 registration/forms.py:57 55 | msgid "Phone Number" 56 | msgstr "" 57 | 58 | #: registration/forms.py:33 registration/forms.py:58 registration/forms.py:83 59 | msgid "Payment Method" 60 | msgstr "" 61 | 62 | #: registration/forms.py:54 63 | msgid "Additional Funding KRW" 64 | msgstr "" 65 | 66 | #: registration/forms.py:81 67 | msgid "Title" 68 | msgstr "" 69 | 70 | #: registration/forms.py:82 71 | msgid "Email" 72 | msgstr "" 73 | 74 | #: registration/models.py:137 75 | msgid "Credit Card only for Korean" 76 | msgstr "" 77 | 78 | #: registration/models.py:138 79 | msgid "Credit Card for Foreign" 80 | msgstr "" 81 | 82 | #: registration/templates/registration/manual_payment.html:6 83 | msgid "Manual Payment" 84 | msgstr "" 85 | 86 | #: registration/templates/registration/payment.html:28 87 | #: registration/templates/registration/status.html:143 88 | #: registration/views.py:110 registration/views.py:359 89 | msgid "Registration" 90 | msgstr "" 91 | 92 | #: registration/templates/registration/registration_detail.html:14 93 | msgid "PyCon Korea 2018" 94 | msgstr "" 95 | 96 | #: registration/templates/registration/status.html:7 97 | msgid "Registration status" 98 | msgstr "" 99 | 100 | #: registration/templates/registration/status.html:9 101 | msgid "Registration is completed" 102 | msgstr "" 103 | 104 | #: registration/templates/registration/status.html:11 105 | msgid "Your registration is completed without any problems" 106 | msgstr "" 107 | 108 | #: registration/templates/registration/status.html:20 109 | #: registration/templates/registration/status.html:94 110 | msgid "E-mail" 111 | msgstr "" 112 | 113 | #: registration/templates/registration/status.html:45 114 | msgid "Phone number" 115 | msgstr "" 116 | 117 | #: registration/templates/registration/status.html:53 118 | #: registration/templates/registration/status.html:98 119 | msgid "Price" 120 | msgstr "" 121 | 122 | #: registration/templates/registration/status.html:58 123 | #: registration/templates/registration/status.html:103 124 | msgid "Additional Funding" 125 | msgstr "" 126 | 127 | #: registration/templates/registration/status.html:63 128 | #: registration/templates/registration/status.html:108 129 | msgid "Transaction ID" 130 | msgstr "" 131 | 132 | #: registration/templates/registration/status.html:67 133 | msgid "Registration datetime" 134 | msgstr "" 135 | 136 | #: registration/templates/registration/status.html:71 137 | msgid "Cancelable Date" 138 | msgstr "" 139 | 140 | #: registration/templates/registration/status.html:83 141 | msgid "Check Registration Receipt" 142 | msgstr "" 143 | 144 | #: registration/templates/registration/status.html:87 145 | msgid "Payment Information" 146 | msgstr "" 147 | 148 | #: registration/templates/registration/status.html:112 149 | msgid "Bank to transfer" 150 | msgstr "" 151 | 152 | #: registration/templates/registration/status.html:116 153 | msgid "Account number to transafer" 154 | msgstr "" 155 | 156 | #: registration/templates/registration/status.html:120 157 | msgid "Account owner name" 158 | msgstr "" 159 | 160 | #: registration/templates/registration/status.html:124 161 | msgid "Payment deadline" 162 | msgstr "" 163 | 164 | #: registration/templates/registration/status.html:128 165 | msgid "Payment check" 166 | msgstr "" 167 | 168 | #: registration/templates/registration/status.html:131 169 | msgid "Not checked yet" 170 | msgstr "" 171 | 172 | #: registration/templates/registration/status.html:133 173 | msgid "Payment checked" 174 | msgstr "" 175 | 176 | #: registration/templates/registration/status.html:140 177 | msgid "There is no registration record" 178 | msgstr "" 179 | 180 | #: registration/views.py:55 181 | msgid "Registration Status" 182 | msgstr "" 183 | 184 | #: registration/views.py:450 185 | msgid "Registration Receipt" 186 | msgstr "" 187 | 188 | #: registration/views.py:469 189 | msgid "Issue Ticket System" 190 | msgstr "" 191 | 192 | #: registration/views.py:486 193 | msgid "Ticket Print" 194 | msgstr "" 195 | -------------------------------------------------------------------------------- /registration/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/registration/management/__init__.py -------------------------------------------------------------------------------- /registration/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/registration/management/commands/__init__.py -------------------------------------------------------------------------------- /registration/management/commands/calculation_attendee.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from django.core.management.base import BaseCommand 4 | 5 | from registration.models import IssueTicket, Registration 6 | 7 | 8 | class Command(BaseCommand): 9 | help = 'Calculating attendee count per Option' 10 | 11 | def handle(self, *args, **options): 12 | all_tickets = IssueTicket.objects.all() 13 | categorized_tickets = {} 14 | 15 | for ticket in all_tickets: 16 | if ticket.registration.option.name in categorized_tickets: 17 | if ticket.registration not in categorized_tickets[ticket.registration.option.name]: 18 | categorized_tickets[ticket.registration.option.name].append(ticket.registration) 19 | else: 20 | categorized_tickets[ticket.registration.option.name] = [ticket.registration] 21 | 22 | all_registration = Registration.objects.all() 23 | 24 | print(datetime.now()) 25 | 26 | for key in categorized_tickets.keys(): 27 | print('{} - {}/{}'.format(key, len(categorized_tickets[key]), 28 | all_registration.filter(option__name=key).count())) 29 | -------------------------------------------------------------------------------- /registration/management/commands/delete_login_token.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | 3 | from django.core.management.base import BaseCommand 4 | 5 | from pyconkr.models import EmailToken 6 | 7 | 8 | class Command(BaseCommand): 9 | help = 'Delete token 10 mins past' 10 | 11 | def handle(self, *args, **options): 12 | filtering_time = datetime.now() - timedelta(minutes=10) 13 | all_email_token = EmailToken.objects.filter(created__lt=filtering_time).all() 14 | all_email_token.delete() 15 | -------------------------------------------------------------------------------- /registration/management/commands/payment_reconciliation.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from django.core.management.base import BaseCommand, CommandError 3 | from registration.models import Registration, Option 4 | from registration.iamporter import Iamporter, get_access_token 5 | from constance import config 6 | 7 | class Command(BaseCommand): 8 | help = 'Cross check paid and registration consistency' 9 | 10 | def handle(self, *args, **options): 11 | eary_bird = Option.objects.get(name='Early Bird') 12 | paid_registrations = \ 13 | Registration.objects.filter(payment_status='paid').exclude(payment_method='bank', option=eary_bird).values_list('merchant_uid', 14 | 'email') 15 | paid_registrations = dict(list(paid_registrations)) 16 | access_token = get_access_token(config.IMP_API_KEY, config.IMP_API_SECRET) 17 | imp_client = Iamporter(access_token) 18 | # Use hard coded date only for pycon 2016. 19 | paid_pg = imp_client.get_paid_list(since=datetime.datetime(2017, 1, 1)) 20 | paid_pg = map(lambda x: (x['merchant_uid'], x['buyer_email']), paid_pg) 21 | paid_pg = dict(paid_pg) 22 | print('registered but not paid') 23 | for registration in paid_registrations: 24 | if registration not in paid_pg: 25 | print(registration) 26 | print(paid_registrations[registration]) 27 | print('paid but not registered') 28 | for pg in paid_pg: 29 | if pg not in paid_registrations: 30 | print(pg) 31 | print(paid_pg[pg]) 32 | -------------------------------------------------------------------------------- /registration/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-03-23 12:29 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='Option', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('name', models.CharField(max_length=50)), 24 | ('description', models.TextField()), 25 | ('is_active', models.BooleanField(default=False)), 26 | ('price', models.IntegerField()), 27 | ], 28 | ), 29 | migrations.CreateModel( 30 | name='Registration', 31 | fields=[ 32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 | ('merchant_uid', models.CharField(max_length=32)), 34 | ('name', models.CharField(max_length=100)), 35 | ('email', models.EmailField(max_length=255)), 36 | ('company', models.CharField(blank=True, max_length=100)), 37 | ('phone_number', models.CharField(max_length=20)), 38 | ('transaction_code', models.CharField(max_length=36)), 39 | ('payment_method', models.CharField(choices=[('card', '\uc2e0\uc6a9\uce74\ub4dc')], default='card', max_length=20)), 40 | ('payment_status', models.CharField(max_length=10)), 41 | ('payment_message', models.CharField(max_length=255, null=True)), 42 | ('vbank_num', models.CharField(blank=True, max_length=255, null=True)), 43 | ('vbank_name', models.CharField(blank=True, max_length=20, null=True)), 44 | ('vbank_date', models.CharField(blank=True, max_length=50, null=True)), 45 | ('vbank_holder', models.CharField(blank=True, max_length=20, null=True)), 46 | ('created', models.DateTimeField(auto_now_add=True)), 47 | ('modified', models.DateTimeField(auto_now=True)), 48 | ('option', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='registration.Option')), 49 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 50 | ], 51 | ), 52 | ] 53 | -------------------------------------------------------------------------------- /registration/migrations/0002_auto_20160323_1428.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-03-23 14:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('registration', '0001_initial'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='registration', 18 | name='option', 19 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='registration.Option'), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /registration/migrations/0003_option_has_additional_price.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-03-31 14:51 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0002_auto_20160323_1428'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='option', 17 | name='has_additional_price', 18 | field=models.BooleanField(default=False), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0004_registration_additional_price.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-04-04 12:56 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0003_option_has_additional_price'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='registration', 17 | name='additional_price', 18 | field=models.IntegerField(default=0), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0005_option_total.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-04-12 18:27 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0004_registration_additional_price'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='option', 17 | name='total', 18 | field=models.IntegerField(default=500), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0006_auto_20160416_1202.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-04-16 03:02 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0005_option_total'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='registration', 17 | name='canceled', 18 | field=models.DateTimeField(blank=True, null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='registration', 22 | name='confirmed', 23 | field=models.DateTimeField(blank=True, null=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='registration', 27 | name='payment_method', 28 | field=models.CharField(choices=[('card', 'Credit Card'), ('bank', 'Bank Transfer')], default='card', max_length=20), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /registration/migrations/0007_auto_20160416_1217.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-04-16 03:17 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0006_auto_20160416_1202'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='payment_message', 18 | field=models.CharField(blank=True, max_length=255, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0008_auto_20160418_2250.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-04-18 13:50 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0007_auto_20160416_1217'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='payment_status', 18 | field=models.CharField(choices=[('ready', 'Ready'), ('paid', 'Paid'), ('deleted', 'Deleted')], default='ready', max_length=10), 19 | ), 20 | migrations.AlterField( 21 | model_name='registration', 22 | name='transaction_code', 23 | field=models.CharField(blank=True, max_length=36), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /registration/migrations/0009_auto_20160501_2332.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.4 on 2016-05-01 14:32 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0008_auto_20160418_2250'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='payment_status', 18 | field=models.CharField(choices=[('ready', 'Ready'), ('paid', 'Paid'), ('deleted', 'Deleted'), ('cancelled', 'Cancelled')], default='ready', max_length=10), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0010_auto_20170428_0007.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-04-27 15:07 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0009_auto_20160501_2332'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='payment_method', 18 | field=models.CharField(choices=[('card', 'Credit Card'), ('bank', 'Bank Transfer'), ('vbank', 'Virtual Bank Transfer')], default='card', max_length=20), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0011_auto_20170515_2228.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.1 on 2017-05-15 13:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0010_auto_20170428_0007'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='payment_method', 18 | field=models.CharField(choices=[('card', 'Credit Card'), ('vbank', 'Virtual Bank Transfer')], default='card', max_length=20), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0012_registration_top_size.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.2 on 2017-06-12 09:33 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0011_auto_20170515_2228'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], default='L', max_length=20), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0013_auto_20170616_1446.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.2 on 2017-06-16 05:46 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0012_registration_top_size'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0014_auto_20170619_1138.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.2 on 2017-06-19 02:38 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0013_auto_20170616_1446'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], default=None, max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0015_auto_20170619_1151.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.2 on 2017-06-19 02:51 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0014_auto_20170619_1138'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], default='', max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0016_auto_20170619_1155.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.2 on 2017-06-19 02:55 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0015_auto_20170619_1151'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], default='', max_length=20), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0017_auto_20170619_1458.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.2 on 2017-06-19 05:58 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0016_auto_20170619_1155'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], default=None, max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0018_auto_20170619_1514.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-06-19 06:14 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0017_auto_20170619_1458'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(blank=True, choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '3XL(115)')], default=None, max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0019_auto_20170630_1534.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-06-30 06:34 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0018_auto_20170619_1514'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='top_size', 18 | field=models.CharField(blank=True, choices=[('small', 'S(85)'), ('medium', 'M(90)'), ('large', 'L(95)'), ('xlarge', 'XL(100)'), ('2xlarge', '2XL(105)'), ('3xlarge', '3XL(110)'), ('4xlarge', '4XL(115)')], default=None, max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0020_auto_20170701_1757.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.1 on 2017-07-01 08:57 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0019_auto_20170630_1534'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='option', 17 | options={'ordering': ['price']}, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /registration/migrations/0021_auto_20170713_1341.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.1 on 2017-07-13 04:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0020_auto_20170701_1757'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='option', 17 | name='cancelable_date', 18 | field=models.DateTimeField(null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='option', 22 | name='is_cancelable', 23 | field=models.BooleanField(default=False), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /registration/migrations/0022_manualpayment.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.3 on 2017-07-15 04:51 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('registration', '0021_auto_20170713_1341'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='ManualPayment', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('title', models.CharField(max_length=100)), 23 | ('price', models.PositiveIntegerField()), 24 | ('merchant_uid', models.CharField(blank=True, db_index=True, max_length=32)), 25 | ('imp_uid', models.CharField(blank=True, max_length=32, null=True)), 26 | ('transaction_code', models.CharField(blank=True, max_length=36)), 27 | ('payment_method', models.CharField(choices=[('card', 'Credit Card')], default='card', max_length=20)), 28 | ('payment_status', models.CharField(choices=[('ready', 'Ready'), ('paid', 'Paid'), ('cancelled', 'Cancelled')], default='ready', max_length=10)), 29 | ('payment_message', models.CharField(blank=True, max_length=255, null=True)), 30 | ('description', models.TextField(blank=True)), 31 | ('created', models.DateTimeField(auto_now_add=True)), 32 | ('modified', models.DateTimeField(auto_now=True)), 33 | ('confirmed', models.DateTimeField(blank=True, null=True)), 34 | ('canceled', models.DateTimeField(blank=True, null=True)), 35 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 36 | ], 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /registration/migrations/0023_issue_manager.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-08-01 11:33 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | import django.utils.timezone 9 | 10 | 11 | class Migration(migrations.Migration): 12 | 13 | dependencies = [ 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ('registration', '0022_manualpayment'), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name='IssueTicket', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('issue_date', models.DateTimeField(default=django.utils.timezone.now)), 24 | ('issuer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 25 | ('registration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='registration.Registration')), 26 | ], 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /registration/migrations/0024_add_extra_fields_option.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.11 on 2018-05-17 19:00 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0023_issue_manager'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='option', 17 | name='begin_at', 18 | field=models.DateTimeField(null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='option', 22 | name='closed_at', 23 | field=models.DateTimeField(null=True), 24 | ), 25 | migrations.AddField( 26 | model_name='option', 27 | name='conference_type', 28 | field=models.CharField(blank=True, choices=[('earlybird', '얼리버드'), ('regular', '일반'), ('company', '법인'), ('patron', '개인후원')], max_length=15, null=True), 29 | ), 30 | migrations.AddField( 31 | model_name='option', 32 | name='event_type', 33 | field=models.CharField(choices=[('conference', '컨퍼런스'), ('tuturial', '튜토리얼'), ('young', '영코더'), ('babycare', '아이돌봄')], default='conference', max_length=15), 34 | ), 35 | migrations.AlterField( 36 | model_name='option', 37 | name='price', 38 | field=models.PositiveIntegerField(), 39 | ), 40 | migrations.AlterUniqueTogether( 41 | name='option', 42 | unique_together=set([('event_type', 'conference_type')]), 43 | ), 44 | ] 45 | -------------------------------------------------------------------------------- /registration/migrations/0025_auto_20180601_0214.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.13 on 2018-05-31 17:14 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0024_add_extra_fields_option'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='payment_method', 18 | field=models.CharField(choices=[('card-korean', 'Credit Card only for Korean'), ('card-foreign', 'Credit Card for Foreign'), ('vbank', 'Virtual Bank Transfer')], default='card-korean', max_length=20), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0026_auto_20180607_1241.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.13 on 2018-06-07 03:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0025_auto_20180601_0214'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='registration', 17 | name='additional_price', 18 | field=models.PositiveIntegerField(default=0), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0027_auto_20180708_2058.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.13 on 2018-07-08 11:58 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0026_auto_20180607_1241'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterUniqueTogether( 16 | name='option', 17 | unique_together=set([]), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /registration/migrations/0027_auto_20180715_2205.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.11 on 2018-07-15 13:05 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0026_auto_20180607_1241'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='option', 17 | name='event_type', 18 | field=models.CharField(choices=[('conference', '컨퍼런스'), ('tutorial', '튜토리얼'), ('young', '영코더'), ('babycare', '아이돌봄')], default='conference', max_length=15), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /registration/migrations/0028_merge_20180723_2159.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.13 on 2018-07-23 12:59 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('registration', '0027_auto_20180715_2205'), 12 | ('registration', '0027_auto_20180708_2058'), 13 | ] 14 | 15 | operations = [ 16 | ] 17 | -------------------------------------------------------------------------------- /registration/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/registration/migrations/__init__.py -------------------------------------------------------------------------------- /registration/static/js/payment.js: -------------------------------------------------------------------------------- 1 | // TODO : i18n 2 | var payment = { 3 | config: {}, 4 | setConfig: function (config) { 5 | this.config = config; 6 | }, 7 | handleResponse: function (response) { 8 | var payment = this; 9 | var $additionalPrice = $('#id_additional_price'); 10 | 11 | response['csrfmiddlewaretoken'] = payment.config.csrf_token; 12 | response['name'] = $('#id_name').val(); 13 | response['email'] = $('#id_email').val(); 14 | response['base_price'] = parseInt(this.config.amount); 15 | response['additional_price'] = parseInt($additionalPrice.val()) ? parseInt($additionalPrice.val()) : 0; 16 | response['company'] = $('#id_company').val(); 17 | response['top_size'] = $('#id_top_size').val(); 18 | response['phone_number'] = $('#id_phone_number').val(); 19 | response['payment_method'] = $('#id_payment_method').val(); 20 | response['option'] = $('#id_option').val(); 21 | 22 | $.ajax({ 23 | method: 'POST', 24 | url: payment.config.payment_url, 25 | data: response, 26 | dataType: 'json' 27 | }).done(function (result) { 28 | if (!result.success) { 29 | alert('결제에 실패했습니다. ' + result.code + ' ' + result.message); 30 | window.location.reload(); 31 | return; 32 | } 33 | alert('결제가 완료되었습니다.'); 34 | window.location.href = payment.config.status_url; 35 | }.bind(this)).fail(function (xhr, status, error) { 36 | alert('결제에 실패했습니다. 다시 시도해 주세요.' + error); 37 | window.location.reload(); 38 | }.bind(this)); 39 | }, 40 | iamportCard: function (initCode, uid, amount) { 41 | var payment = this; 42 | 43 | IMP.SBCR.init(initCode); 44 | IMP.SBCR.onetime({ 45 | merchant_uid: uid, 46 | amount: amount, 47 | vat: 0 48 | }, function (response) { 49 | if (!response.token) { 50 | alert(response.message); 51 | return false; 52 | } 53 | payment.handleResponse(response); 54 | }.bind(this)); 55 | }, 56 | init: function (config) { 57 | this.setConfig(config); 58 | var payment = this; 59 | 60 | $('#submit-id-submit').attr('disabled', false); 61 | $('#registration-form').submit(function (e) { 62 | e.preventDefault(); 63 | var $additionalPrice = $('#id_additional_price'); 64 | var additionalPrice = parseInt($additionalPrice.val()) ? parseInt($additionalPrice.val()) : 0; 65 | var paymentMethod = $('#id_payment_method').val(); 66 | var totalPrice = parseInt(payment.config.amount) + additionalPrice; 67 | 68 | if (paymentMethod === 'card-korean') { 69 | payment.iamportCard(payment.config.IMP_DOM_USER_CODE, payment.config.uid, totalPrice); 70 | } else if (paymentMethod === 'card-foreign') { 71 | payment.iamportCard(payment.config.IMP_INTL_USER_CODE, payment.config.uid, totalPrice); 72 | } else if (paymentMethod === 'vbank') { 73 | IMP.init(payment.config.IMP_DOM_USER_CODE); 74 | IMP.request_pay({ 75 | pg: 'nice', 76 | pay_method: 'vbank', 77 | merchant_uid: payment.config.uid, 78 | name: $('#id_option').val(), 79 | amount: totalPrice, 80 | buyer_email: $('#id_email').val(), 81 | buyer_name: $('#id_name').val(), 82 | buyer_tel: $('#id_phone_number').val(), 83 | buyer_addr: '', 84 | buyer_postcode: '' 85 | }, function (rsp) { 86 | if (rsp.success) { 87 | payment.handleResponse(rsp); 88 | } else { 89 | var msg = '결제에 실패하였습니다.'; 90 | msg += '에러내용 : ' + rsp.error_msg; 91 | alert(msg); 92 | } 93 | }); 94 | } else { 95 | // ????? 96 | } 97 | }); 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /registration/static/stamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pythonkr/pyconkr-2018/d2fe3b41d487875a6616319adddf8ee3d28dc7a2/registration/static/stamp.jpg -------------------------------------------------------------------------------- /registration/templates/registration/cancellation_result.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n l10n %} 3 | {% load admin_urls %} 4 | 5 | {% block content %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for obj in results %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% endfor %} 30 | 31 |
ID이름이메일옵션Merchant UID취소 여부비고
{{ obj.id }}{{ obj.name }}{{ obj.email }}{{ obj.option }}{{ obj.merchant_uid }}{{ obj.cancel_status }}{{ obj.cancel_reason }}
32 |

33 | Back to list 34 |

35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 29 | 30 | 31 |
32 |

참석 확인증
(Confirmation of the attendance)

33 |
34 |

35 |

36 | 성 명 (Name) : {{ registration.name }}
37 | 소 속 (Organization) : {{ registration.company }} 38 |

39 |

40 |

41 |

42 | 위 사람은 파이콘 한국에서 주최하는 파이콘 한국 2018에 참가하였음을 확인합니다.
43 | This is to certify that the above-mentioned person has visited the conference for 2 days at PyCon Korea 2018 44 |

45 |

46 |

47 |

48 | 1. 일시 (Date) : 2018년 8월 18일, 19일
(August 18th and 19th, 2018)
49 |

50 | 2. 장소 (Venue) : 서울특별시 강남구 영동대로 513 코엑스
(COEX, Yeongdong-daero 513, Gangnam-gu, Seoul)
51 |

52 | 3. 주최 (Hosted by) : 파이콘 한국 준비위원회
(PyCon Korea Organizing Team)
53 |

54 |

55 |

56 |

{{ year }}. {{ month }}. {{ day }}

57 |

58 |

59 | 사단법인 파이썬사용자모임 대표 배권한
(Kwon-Han Bae, President of Python User Group)
61 |

62 |

63 |
64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_not_registered.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 7 | 8 | 9 |
10 |

파이콘 한국 2018에 등록하지 않았습니다. (Not Registered)

11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_not_visited.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 7 | 8 | 9 |
10 |

파이콘 한국 2018에 참석하지 않았습니다. (Not Visited)

11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_sprint.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 29 | 30 | 31 |
32 |

참석 확인증
(Confirmation of the attendance)

33 |
34 |

35 |

36 | 성 명 (Name) : {{ user.profile.name }}
37 | 소 속 (Organization) : {{ user.profile.organization }} 38 |

39 |

40 |

41 |

42 | 위 사람은 파이콘 한국에서 주최하는 파이콘 한국 2018 스프린트 프로그램에 참가하였음을 확인합니다.
43 | This is to certify that the above-mentioned person has visited the Sprint program at PyCon Korea 2018 44 |

45 |

46 |

47 |

48 | 1. 일시 (Date) : 2018년 8월 15일, 17일
(August 15th and 17th, 2018)
49 |

50 | 2. 장소 (Venue) : 서울특별시 강남구 영동대로 513 코엑스
(COEX, Yeongdong-daero 513, Gangnam-gu, Seoul)
51 |

52 | 3. 주최 (Hosted by) : 파이콘 한국 준비위원회
(PyCon Korea Organizing Team)
53 |

54 |

55 |

56 |

{{ year }}. {{ month }}. {{ day }}

57 |

58 |

59 | 사단법인 파이썬사용자모임 대표 배권한
(Kwon-Han Bae, President of Python User Group)
61 |

62 |

63 |
64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_sprint_not_registered.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 7 | 8 | 9 |
10 |

파이콘 한국 2018 스프린트 프로그램에 등록하지 않았습니다. (Not Registered)

11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_tutorial.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 29 | 30 | 31 |
32 |

참석 확인증
(Confirmation of the attendance)

33 |
34 |

35 |

36 | 성 명 (Name) : {{ registration.name }}
37 | 소 속 (Organization) : {{ registration.company }} 38 |

39 |

40 |

41 |

42 | 위 사람은 파이콘 한국에서 주최하는 파이콘 한국 2018 튜토리얼 프로그램에 참가하였음을 확인합니다.
43 | This is to certify that the above-mentioned person has visited the Tutorial program at PyCon Korea 2018 44 |

45 |

46 |

47 |

48 | 1. 일시 (Date) : 2018년 8월 15일
(August 15th, 2018)
49 |

50 | 2. 장소 (Venue) : 서울특별시 강남구 영동대로 513 코엑스
(COEX, Yeongdong-daero 513, Gangnam-gu, Seoul)
51 |

52 | 3. 주최 (Hosted by) : 파이콘 한국 준비위원회
(PyCon Korea Organizing Team)
53 |

54 |

55 |

56 |

{{ year }}. {{ month }}. {{ day }}

57 |

58 |

59 | 사단법인 파이썬사용자모임 대표 배권한
(Kwon-Han Bae, President of Python User Group)
61 |

62 |

63 |
64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_tutorial_not_registered.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 7 | 8 | 9 |
10 |

파이콘 한국 2018 튜토리얼 프로그램에 등록하지 않았습니다. (Not Registered)

11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /registration/templates/registration/certificates_tutorial_not_visited.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 7 | 8 | 9 |
10 |

파이콘 한국 2018 튜토리얼 프로그램에 참석하지 않았습니다. (Not Visited)

11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /registration/templates/registration/checkin_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n humanize %} 3 | 4 | {% block head-include %} 5 | 6 | 7 | 8 | 13 | {% endblock %} 14 | 15 | {% block content %} 16 |
17 | 스프린트명 : {{ sprint.title }}
18 |
19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% for checkin in checkins %} 31 | 32 | 33 | 34 | 35 | 36 | {% endfor %} 37 | 38 |
emailnamecreated_at
{{ checkin.user.email }}{{ checkin.user.profile.name }}{{ checkin.created }}
39 |
40 | {% endblock %} 41 | -------------------------------------------------------------------------------- /registration/templates/registration/info.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n humanize %} 3 | 4 | {% block content %} 5 |
6 | {% if is_registered %} 7 |
8 |

이미 등록되었습니다.

9 |

10 | 등록 확인하기 11 |

12 |
13 | {% else %} 14 | {% if not options %} 15 |
등록 기간이 아닙니다
16 | {% else %} 17 |
18 | {% for option in options %} 19 |
20 |

{{ option.name }}

21 |

{% autoescape off %}{{ option.description }}{% endautoescape %}

22 |

Price: {{ option.price|intcomma }} KRW

23 |

Cancelable Date : 24 | {% if option.is_cancelable %} 25 | {{ option.cancelable_date|date:"Y년 M d일 D a g시까지"}} 26 | {% else %} 27 | 환불 불가(Not Refundable) 28 | {% endif %} 29 |

30 |

31 | {% if option.is_sold_out %} 32 |

33 | {{ option.name }}-SOLD OUT 34 |
35 | {% elif option.is_opened %} 36 | 37 | {{ option.name }} 38 | 39 | {% else %} 40 | 41 | {{ option.begin_at|date:"Y년 M d일 D a g" }}시 오픈 예정 42 | 43 | {% endif %} 44 |

45 |
46 | {% endfor %} 47 |
48 | {% endif %} 49 | {% endif %} 50 |
51 | {% endblock %} 52 | -------------------------------------------------------------------------------- /registration/templates/registration/issue_print.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 78 | 79 | 80 |
81 |
82 | 현재 발권횟수: {{ registration.issueticket_set.count }} 83 |
84 |
85 |
    86 |
  • 결제시 이름: {{ registration.name }}
  • 87 |
  • 프로필 이름: {{ registration.user.profile.name }}
  • 88 |
89 |
90 | 91 |
92 |
93 |
94 |
{{ name }}
95 |
{{ company }}
96 |
97 | {% if additional_ticket is not None %} 98 |
99 | {% if additional_ticket.patron %} 100 |
개인후원 기념품을 수령해가세요.
101 | {% endif %} 102 | {% if additional_ticket.speaker %} 103 |
발표자 기념품을 수령해가세요.
104 | {% endif %} 105 | {% if additional_ticket.baby_care %} 106 |
아이돌봄 명찰을 수령해주세요.
107 | {% endif %} 108 | {% if additional_ticket.young_coder %} 109 |
영코더 추가 등록 절차를 진행해주세요.
110 | {% endif %} 111 |
112 | {% endif %} 113 |
114 | 115 | 116 | 117 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /registration/templates/registration/issue_ticket.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n humanize %} 3 | {% load staticfiles %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block content %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for user in registration %} 18 | 19 | 20 | 21 | 22 | 32 | 33 | {% endfor %} 34 | 35 |
이름이메일셔츠사이즈관리
{{ user.name }}{{ user.email }}{{ user.top_size }} 23 |
24 | 발권 27 | 관리 30 |
31 |
36 | 37 | 38 | {% endblock %} 39 | 40 | {% block head-include %} 41 | 42 | {% endblock %} 43 | 44 | {% block script %} 45 | 46 | 47 | 48 | 60 | 61 | {% endblock %} 62 | -------------------------------------------------------------------------------- /registration/templates/registration/manual_payment.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load crispy_forms_tags %} 4 | 5 | {% block content %} 6 |

{% trans 'Manual Payment' %}

7 |
8 |
{% crispy form %}
9 |
10 | {% endblock %} 11 | 12 | {% block head-include %} 13 | 14 | 15 | 68 | {% endblock %} 69 | -------------------------------------------------------------------------------- /registration/templates/registration/payment.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block head-include %} 7 | 8 | 9 | 10 | 25 | {% endblock %} 26 | 27 | {% block content %} 28 |

{% trans 'Registration' %}

29 |
30 |
결제를 완료하시면 신청이 됩니다.
(*) 는 필수 입력 항목입니다.
31 |
{% crispy form %}
32 |
33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /registration/templates/registration/payment_babycare.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block head-include %} 7 | 8 | 9 | 10 | 25 | {% endblock %} 26 | 27 | {% block content %} 28 |

아이돌봄 신청

29 |
30 | {% if sold_out %} 31 |
아이돌봄 프로그램이 모두 판매되었습니다.
32 | {% else %} 33 | {% if has_conference_ticket %} 34 |
아래의 모든 항목을 채워주세요.
구글 설문을 응해주시지 않으면 참여가 어려울 수 있습니다.
35 |
36 | 40 |
41 |
아래의 폼 입력 후 결제를 완료하시면 신청이 됩니다.
(*) 는 필수 입력 항목입니다.
42 |
{% crispy form %}
43 | 44 | {% else %} 45 |
아이돌봄은 파이콘 한국 2018 컨퍼런스 티켓 구매자에 한해 구매가 가능합니다.
46 | {% endif %} 47 | {% endif %} 48 |
49 | {% endblock %} 50 | 51 | -------------------------------------------------------------------------------- /registration/templates/registration/payment_youngcoder.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block head-include %} 7 | 8 | 9 | 10 | 25 | {% endblock %} 26 | 27 | {% block content %} 28 |

영코더 신청

29 |
30 | {% if sold_out %} 31 |
영코더 프로그램이 모두 판매되었습니다.
32 | {% else %} 33 |
아래의 모든 항목을 채워주세요.
구글 설문을 응해주시지 않으면 참여가 어려울 수 있습니다.
34 |
35 | {% if option_id == 17 %} 36 | 40 | {% else %} 41 | 42 | 46 | {% endif %} 47 |
48 |
아래의 폼 입력 후 결제를 완료하시면 신청이 됩니다.
(*) 는 필수 입력 항목입니다.
49 |
{% crispy form %}
50 | 51 | {% endif %} 52 |
53 | {% endblock %} 54 | 55 | -------------------------------------------------------------------------------- /registration/templates/registration/registration_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n humanize %} 3 | {% load thumbnail %} 4 | {% load crispy_forms_tags %} 5 | {% load staticfiles %} 6 | 7 | {% block content %} 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 |
Name {{ registration.name }}
Ticket Type {% trans "PyCon Korea 2018" %} - {{ registration.option.name }}
Price {{ registration.option.price|add:registration.additional_price|intcomma }}
Provider Python Korea Inc.
Chair man. Kwon-Han, Bae
21 | 22 |
Provider Company Number 338-82-00046
28 |
29 | {% endblock %} 30 | 31 | -------------------------------------------------------------------------------- /registration/templates/registration/registration_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n humanize %} 3 | 4 | {% block head-include %} 5 | 6 | 7 | 8 | 13 | {% endblock %} 14 | 15 | {% block content %} 16 |
17 | 티켓 타입 : {{ option.event_type }}
18 | 티켓 옵션 : {{ option.name }}
19 | 티켓 가격 : {{ option.price }}
20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {% for regi in registrations %} 33 | 34 | 35 | 36 | 37 | 38 | {% endfor %} 39 | 40 |
emailnamecreated_at
{{ regi.email }}{{ regi.name }}{{ regi.created }}
41 |
42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /registration/templates/registration/sprint_checkin.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n humanize %} 3 | {% load staticfiles %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block content %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for checkin in checkins %} 17 | 18 | 19 | 20 | 30 | 31 | {% endfor %} 32 | 33 |
이름이메일관리
{{ checkin.user.profile.name }}{{ checkin.user.email }} 21 |
22 | 발권 25 | 관리 28 |
29 |
34 | 35 | 36 | {% endblock %} 37 | 38 | {% block head-include %} 39 | 40 | {% endblock %} 41 | 42 | {% block script %} 43 | 44 | 45 | 46 | 58 | 59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /registration/templates/registration/sprint_print.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 72 | 73 | 74 |
75 |
76 |
    77 |
  • 출력이름 이름: {{ name }}
  • 78 |
  • 출력이름 회사: {{ company }}
  • 79 |
  • 참여 스프린트: {{ sprint_title }}
  • 80 |
81 |
82 | 83 |
84 |
85 |
86 |
{{ name }}
87 |
{{ company }}
88 |
{{ sprint_title }}
89 |
90 |
91 | 92 | 93 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /registration/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import datetime 3 | 4 | from unittest import mock 5 | from django.test import TestCase 6 | from django.contrib.auth import get_user_model 7 | from django.contrib.auth.models import Group 8 | from django.core.urlresolvers import reverse 9 | from constance.test import override_config 10 | from django_dynamic_fixture import G 11 | 12 | from .models import Option, Registration, IssueTicket 13 | 14 | User = get_user_model() 15 | 16 | 17 | @override_config(REGISTRATION_OPEN=datetime.date.today()-datetime.timedelta(days=1), REGISTRATION_CLOSE=datetime.date.today()+datetime.timedelta(days=1)) 18 | class RegistrationTest(TestCase): 19 | def test_patron_has_additional_price(self): 20 | option = Option.objects.create(name='patron', price=1000, has_additional_price=True, is_active=True) 21 | user = User.objects.create_user('testname', 'test@test.com', 'testpassword') 22 | self.client.login(username='testname', password='testpassword') 23 | response = self.client.get(reverse('registration_payment', args=[option.id])) 24 | self.assertIn('additional_price', response.context['form'].fields) 25 | 26 | def test_transaction_id_is_not_required(self): 27 | registration = G(Registration, transaction_code='') 28 | self.assertNotEqual(registration.id, None) 29 | 30 | @mock.patch('registration.views.get_access_token') 31 | @mock.patch('registration.views.Iamporter') 32 | def test_vbank_status_update_via_iamport_callback(self, Iamporter, get_access_token): 33 | get_access_token.return_value = 'test token' 34 | iamporter = Iamporter.return_value 35 | # make registration object for test 36 | registration = G(Registration, payment_method='vbank', payment_status='ready') 37 | iamporter.find_by_merchant_uid.return_value = dict( 38 | merchant_uid=registration.merchant_uid, 39 | status='paid' # yes i wanna make status to paid 40 | ) 41 | # WOW it's so easy. I love ddf. 42 | # let's make a callback parameter 43 | callback_param = dict( 44 | merchant_uid=registration.merchant_uid, 45 | imp_uid='whatever... we dont care.', 46 | status='ready' # acctually i wanna make status to paid 47 | ) 48 | 49 | response = self.client.post(reverse('registration_callback'), callback_param) 50 | self.assertEqual(response.status_code, 200) 51 | registration = Registration.objects.get(id=registration.id) 52 | self.assertEqual(registration.payment_status, 'paid') 53 | 54 | 55 | class IssueTicketTest(TestCase): 56 | def test_inner_group_only(self): 57 | response = self.client.get(reverse('registration_issue')) 58 | self.assertNotEqual(response.status_code, 200) 59 | login_user = User.objects.create_user('test@user.com', 'test@user.com', 60 | 'testpass') 61 | self.client.login(username='test@user.com', password='testpass') 62 | response = self.client.get(reverse('registration_issue')) 63 | self.assertNotEqual(response.status_code, 200) 64 | group = G(Group, name='volunteer') 65 | login_user.groups.add(group) 66 | response = self.client.get(reverse('registration_issue')) 67 | self.assertEqual(response.status_code, 200) 68 | 69 | def test_incr_issue_count(self): 70 | login_user = User.objects.create_user('test@user.com', 'test@user.com', 71 | 'testpass') 72 | G(Registration, payment_status='paid', user=login_user) 73 | group = G(Group, name='volunteer') 74 | login_user.groups.add(group) 75 | self.client.login(username='test@user.com', password='testpass') 76 | response = self.client.get(reverse('registration_issue_submit')) 77 | self.assertEqual(response.status_code, 405) # Because POST only 78 | response = self.client.post(reverse('registration_issue_submit'), 79 | {'user_id': login_user.id}) 80 | issue_count = IssueTicket.objects.filter(registration__user=login_user).count() 81 | self.assertEqual(issue_count, 1) 82 | -------------------------------------------------------------------------------- /registration/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.contrib.auth.decorators import login_required 3 | 4 | from . import views 5 | 6 | urlpatterns = [ 7 | url(r'^purchase/$', views.index, name='registration_index'), 8 | url(r'^status/(\d*)/$', views.status, name='registration_status'), 9 | url(r'^list/(\d*)/$', views.registrations, name='registration_list'), 10 | url(r'^checkins/(\d*)/$', views.checkins, name='registration_checkins'), 11 | url(r'^payment/(\d*)/$', views.payment, name='registration_payment'), 12 | url(r'^payment/$', views.payment_process, name='registration_payment'), 13 | url(r'^payment/callback/$', views.payment_callback, name='registration_callback'), 14 | url(r'^receipt/$', 15 | login_required(views.RegistrationReceiptDetail.as_view()), name='registration_receipt'), 16 | url(r'^payment/manual/(\d+)/$', views.manual_registration, name='manual_registration'), 17 | url(r'^payment/manual/payment/$', views.manual_payment_process, name='manual_payment'), 18 | url(r'^certificates/$', login_required(views.certificates), name='certificates'), 19 | url(r'^certificates_tutorial/$', login_required(views.certificates_tutorial), name='certificates_tutorial'), 20 | url(r'^certificates_sprint/$', login_required(views.certificates_sprint), name='certificates_sprint'), 21 | url(r'^issue/$', views.issue, name='registration_issue'), 22 | url(r'^issue/submit/$', views.issue_submit, name='registration_issue_submit'), 23 | url(r'^issue/print/(?P\d+)/$', views.issue_print, name='registration_issue_print'), 24 | url(r'^sprint/$', views.sprint, name='sprint_checkin'), 25 | url(r'^sprint/print/(?P\d+)/$', views.sprint_print, name='sprint_checkin_print'), 26 | ] 27 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | sphinx 3 | pytest 4 | codecov 5 | -------------------------------------------------------------------------------- /requirements-prod.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | uwsgi 3 | gevent 4 | psycopg2 5 | raven 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | appdirs==1.4.3 2 | defusedxml==0.5.0 3 | Django<1.12 4 | django-allauth==0.32.0 5 | django-constance==2.0.0 6 | django-crispy-forms==1.6.1 7 | django-csv-exports==1.0.3 8 | django-dynamic-fixture==1.9.5 9 | django-jsonfield==1.0.1 10 | django-modeltranslation==0.12.1 11 | django-picklefield==0.3.2 12 | django-rosetta==0.7.13 13 | django-summernote==0.8.7 14 | iamport-rest-client==0.7.0 15 | microsofttranslator==0.8 16 | oauthlib==2.0.2 17 | olefile==0.44 18 | packaging==16.8 19 | Pillow==4.1.0 20 | polib==1.0.8 21 | pyparsing==2.2.0 22 | python3-openid==3.1.0 23 | pytz==2017.2 24 | requests==2.13.0 25 | requests-oauthlib==0.8.0 26 | six==1.10.0 27 | sorl-thumbnail==12.3 28 | --------------------------------------------------------------------------------