├── .coveragerc ├── .gitignore ├── .travis.yml ├── .tx └── config ├── Dockerfile ├── LICENSE ├── MANIFEST.in ├── README.rst ├── Vagrantfile ├── colab ├── __init__.py ├── accounts │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── backends.py │ ├── context_processors.py │ ├── filters.py │ ├── fixtures │ │ └── test_user.json │ ├── forms.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_user_needs_update.py │ │ ├── 0003_auto_20141218_1755.py │ │ ├── 0004_auto_20150311_1818.py │ │ ├── 0005_auto_20150312_1454.py │ │ ├── 0006_auto_20150828_1719.py │ │ ├── 0007_auto_20151105_0120.py │ │ └── __init__.py │ ├── models.py │ ├── signals.py │ ├── tasks.py │ ├── templates │ │ ├── accounts │ │ │ ├── emails │ │ │ │ └── email_verification.txt │ │ │ ├── manage_subscriptions.html │ │ │ ├── user_create_form.html │ │ │ ├── user_detail.html │ │ │ └── user_update_form.html │ │ ├── emails │ │ │ └── create_list_confirmation.txt │ │ ├── registration │ │ │ ├── login.html │ │ │ ├── password_change_form_custom.html │ │ │ ├── password_reset_complete_custom.html │ │ │ ├── password_reset_confirm_custom.html │ │ │ ├── password_reset_done_custom.html │ │ │ ├── password_reset_email_custom.html │ │ │ └── password_reset_form_custom.html │ │ ├── search │ │ │ ├── indexes │ │ │ │ └── accounts │ │ │ │ │ └── user_text.txt │ │ │ └── user_search_preview.html │ │ └── widgets │ │ │ ├── collaboration_chart.html │ │ │ └── latest_contributions.html │ ├── templatetags │ │ ├── __init__.py │ │ └── gravatar.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_context_processor.py │ │ ├── test_email_validation.py │ │ ├── test_forms.py │ │ ├── test_request.py │ │ ├── test_tasks.py │ │ ├── test_user.py │ │ ├── test_utils_validators.py │ │ ├── test_view_signup.py │ │ └── utils.py │ ├── urls.py │ ├── utils │ │ ├── __init__.py │ │ ├── email.py │ │ └── validators.py │ ├── views.py │ └── widgets │ │ ├── __init__.py │ │ ├── collaboration_chart.py │ │ └── latest_contributions.py ├── celery.py ├── conf │ ├── __init__.py │ └── plugin_template │ │ ├── setup.py │ │ ├── src │ │ └── app_name │ │ │ ├── __init__.py │ │ │ ├── apps.py │ │ │ ├── data_importer.py │ │ │ ├── diazo.xml │ │ │ ├── models.py │ │ │ ├── search_indexes.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ └── tests │ │ ├── __init__.py │ │ ├── colab_settings.py │ │ ├── plugins.d │ │ └── app_name.py │ │ ├── runtests.py │ │ └── test_plugin.py ├── exceptions.py ├── home │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── context_processors.py │ ├── models.py │ ├── tests.py │ └── views.py ├── locale │ ├── en │ │ └── LC_MESSAGES │ │ │ ├── django.mo │ │ │ └── django.po │ └── pt_BR │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── management │ ├── __init__.py │ ├── commands │ │ ├── __init__.py │ │ ├── celery.py │ │ ├── initconfig.py │ │ ├── initdb.py │ │ ├── initwidgetsconfig.py │ │ └── startplugin.py │ └── tests │ │ ├── __init__.py │ │ ├── test_celery_command.py │ │ ├── test_initconfig_command.py │ │ └── test_startplugin.py ├── middlewares │ ├── __init__.py │ ├── cookie_middleware.py │ ├── models.py │ ├── redirect_login.py │ └── tests │ │ ├── __init__.py │ │ ├── test_cookie_middleware.py │ │ └── test_redirect_login.py ├── plugins │ ├── __init__.py │ ├── apps.py │ ├── conf.py │ ├── context_processors.py │ ├── data │ │ ├── __init__.py │ │ ├── base_importer.py │ │ └── tasks.py │ ├── exceptions.py │ ├── fixtures │ │ └── sample_user_plugin.json │ ├── helpers.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_auto_20160106_1843.py │ │ └── __init__.py │ ├── models.py │ ├── tasks.py │ ├── templates │ │ └── plugins │ │ │ └── menu_template.html │ ├── templatetags │ │ ├── __init__.py │ │ ├── plugins.py │ │ └── set_var.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_context_processors.py │ │ ├── test_helpers.py │ │ ├── test_tasks.py │ │ ├── test_templatetags.py │ │ ├── test_timestamp.py │ │ └── test_views.py │ ├── urls.py │ ├── utils │ │ ├── __init__.py │ │ ├── apps.py │ │ ├── collaborations.py │ │ ├── filters_importer.py │ │ ├── menu.py │ │ ├── models.py │ │ ├── signals.py │ │ └── tests │ │ │ ├── __init__.py │ │ │ ├── test_apps.py │ │ │ ├── test_collaboration.py │ │ │ └── test_signals.py │ └── views.py ├── queue │ ├── __init__.py │ └── command.py ├── rss │ ├── __init__.py │ ├── feeds.py │ └── urls.py ├── search │ ├── __init__.py │ ├── admin.py │ ├── base_indexes.py │ ├── fixtures │ │ ├── __init__.py │ │ └── test_data.json │ ├── forms.py │ ├── models.py │ ├── templates │ │ ├── message-preview.html │ │ ├── search-base.html │ │ └── search │ │ │ ├── includes │ │ │ └── search_filters.html │ │ │ ├── search-user-preview.html │ │ │ └── search.html │ ├── templatetags │ │ ├── __init__.py │ │ ├── get_operations.py │ │ ├── search_get.py │ │ └── search_preview_templates.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_base_index.py │ │ ├── test_search_view.py │ │ └── test_templatetags.py │ ├── urls.py │ ├── utils │ │ ├── __init__.py │ │ └── url.py │ └── views.py ├── settings.py ├── signals │ ├── __init__.py │ ├── exceptions.py │ ├── signals.py │ └── tests │ │ ├── __init__.py │ │ └── test_signals.py ├── static │ ├── css │ │ ├── footer.css │ │ ├── header.css │ │ └── screen.css │ ├── img │ │ ├── COPYRIGHT │ │ ├── cc_by_sa.png │ │ ├── fav.ico │ │ ├── logo.svg │ │ ├── plus.png │ │ ├── rss.png │ │ ├── user.png │ │ └── x.png │ └── third-party │ │ ├── bootstrap-datetimepicker │ │ ├── README │ │ ├── css │ │ │ └── bootstrap-datetimepicker.min.css │ │ └── js │ │ │ ├── bootstrap-datetimepicker.min.js │ │ │ └── locales │ │ │ ├── bootstrap-datetimepicker.es.js │ │ │ └── bootstrap-datetimepicker.pt-BR.js │ │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap-theme.min.css │ │ │ └── bootstrap.min.css │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ └── js │ │ │ └── bootstrap.min.js │ │ ├── chartjs │ │ └── js │ │ │ └── Chart.min.js │ │ ├── chroma │ │ └── js │ │ │ └── chroma.min.js │ │ ├── font-awesome │ │ ├── css │ │ │ ├── font-awesome-ie7.min.css │ │ │ └── font-awesome.min.css │ │ └── font │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ └── fontawesome-webfont.woff │ │ ├── highcharts │ │ └── js │ │ │ └── highcharts.js │ │ ├── jquery-2.0.3.min.js │ │ ├── jquery.cookie.js │ │ ├── jquery.debouncedresize.js │ │ └── ribbon │ │ ├── gh-fork-ribbon.css │ │ └── gh-fork-ribbon.ie.css ├── super_archives │ └── tests │ │ └── test_utils_collaborations.py ├── templates │ ├── 403.html │ ├── 404.html │ ├── 500.html │ ├── base.html │ ├── doughnut-chart.html │ ├── footer.html │ ├── header-slim.html │ ├── header.html │ ├── home.html │ ├── includes │ │ └── google_analytics.html │ └── pizza-chart.html ├── tz │ ├── __init__.py │ ├── middleware.py │ ├── templates │ │ └── tz │ │ │ └── set_utc_offset.html │ └── tests │ │ ├── __init__.py │ │ └── test_middleware.py ├── urls.py ├── utils │ ├── __init__.py │ ├── conf.py │ ├── highlighting.py │ ├── runner.py │ └── tests │ │ ├── __init__.py │ │ ├── colab_settings.py │ │ ├── plugins.d │ │ ├── gitlab.py │ │ ├── noosfero.py │ │ ├── plugin_test │ │ └── spb.py │ │ └── test_conf.py ├── widgets │ ├── __init__.py │ ├── admin.py │ ├── dashboard │ │ ├── __init__.py │ │ ├── dashboard_collaboration_graph.py │ │ └── dashboard_latest_collaborations.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── profile_widget.py │ ├── templates │ │ └── widgets │ │ │ ├── dashboard_collaboration_graph.html │ │ │ └── dashboard_latest_collaborations.html │ ├── templatetags │ │ ├── __init__.py │ │ └── widgets_tag.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_profile_widget.py │ │ ├── test_widget_manager.py │ │ └── test_widgets.py │ ├── views.py │ └── widget_manager.py └── wsgi.py ├── diagrama_classes.asta ├── docker-compose.yml ├── docs ├── Makefile └── source │ ├── conf.py │ ├── dev.rst │ ├── index.rst │ ├── plugindev.rst │ ├── static │ └── colab-basics.jpg │ └── user.rst ├── features ├── environment.py ├── home_redirect.feature ├── profile_edition.feature ├── steps │ ├── user_steps.py │ └── web_steps.py ├── user_sign_in.feature └── user_sign_up.feature ├── misc ├── etc │ ├── colab │ │ ├── gunicorn.py │ │ ├── plugins.d │ │ │ ├── audiencias.py │ │ │ ├── discourse.py │ │ │ ├── edemocracia.py │ │ │ ├── tos.py │ │ │ └── wikilegis.py │ │ ├── settings.d │ │ │ ├── 01-database.py │ │ │ ├── 02-memcached.py │ │ │ └── 03-logging.py │ │ ├── settings.py │ │ └── widgets.d │ │ │ ├── audiencias_widgets.py │ │ │ ├── discourse_widgets.py │ │ │ └── wikilegis_widgets.py │ ├── cron.d │ │ ├── colab-audiencias │ │ └── colab-wikilegis │ └── nginx │ │ └── conf.d │ │ └── colab.conf └── lib │ └── systemd │ └── system │ ├── celerybeat.service │ ├── celeryd.service │ └── colab.service ├── scripts ├── remove-all-containers.sh ├── remove-all-volumes.sh └── stop-all-containers.sh ├── setup.cfg ├── setup.py ├── start-colab.sh ├── tests ├── __init__.py ├── colab_settings.py ├── run.py ├── settings.d │ └── settings.py ├── test_data.json └── widgets.d │ ├── charts_widget.py │ └── dashboard_widget.py └── vagrant ├── bootstrap.sh ├── centos.sh ├── misc └── etc │ ├── default │ ├── celerybeat │ └── celeryd │ └── init.d │ ├── celerybeat │ ├── celeryd │ └── solr ├── provision.sh ├── solr └── start.sh └── ubuntu.sh /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | */migrations/* 4 | */tests/* 5 | test_*.py 6 | */__init__.py 7 | */urls.py 8 | */settings.py 9 | */tests.py 10 | colab/celery.py 11 | colab/wsgi.py 12 | source = 13 | colab/ 14 | 15 | [report] 16 | precision = 2 17 | show_missing = True 18 | 19 | [html] 20 | directory = coverage_report/ 21 | title = Colab test coverage 22 | 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.log 3 | *.pot 4 | *.pyc 5 | *.pyo 6 | *.egg* 7 | local_settings.py 8 | project_cfg.py 9 | 10 | *.swp 11 | *.sqlite3 12 | *.db 13 | .DS_Store 14 | .vagrant 15 | 16 | ext/ 17 | *.egg-info/ 18 | dist/ 19 | 20 | # Coverage 21 | .coverage 22 | coverage_report/ 23 | 24 | # Whoosh Index 25 | tests/whoosh_index/ 26 | colab/whoosh_index/ 27 | 28 | # Open Build System 29 | .obs/ 30 | 31 | # Documentation build 32 | docs/build 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | sudo: false 4 | 5 | python: 6 | - "2.7" 7 | 8 | addons: 9 | apt: 10 | packages: 11 | - xvfb 12 | - firefox 13 | 14 | env: 15 | global: 16 | - COLAB_SETTINGS=tests/colab_settings.py 17 | 18 | install: 19 | - pip install coveralls flake8 behave behave_django selenium 20 | - pip install . 21 | 22 | script: 23 | - python setup.py test 24 | - xvfb-run -a colab-admin behave --format=progress 25 | - flake8 colab 26 | 27 | after_success: 28 | - coveralls 29 | 30 | notifications: 31 | irc: 32 | channels: 33 | - "chat.freenode.net#colab" 34 | on_success: change 35 | on_failure: always 36 | use_notice: true 37 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [colab.colab] 5 | file_filter = colab/locale//LC_MESSAGES/django.po 6 | source_file = colab/locale/en/LC_MESSAGES/django.po 7 | source_lang = en 8 | type = PO 9 | 10 | [colab.super_archives] 11 | file_filter = colab/super_archives/locale//LC_MESSAGES/django.po 12 | source_file = colab/super_archives/locale/en/LC_MESSAGES/django.po 13 | source_lang = en 14 | type = PO 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM labhackercd/alpine-python2-nodejs 2 | 3 | ENV BUILD_PACKAGES python-dev python3 python3-dev linux-headers \ 4 | git ca-certificates gcc postgresql-dev build-base bash \ 5 | postgresql-client gettext libxml2-dev libxslt-dev zlib-dev jpeg-dev 6 | 7 | RUN apk add --update --no-cache $BUILD_PACKAGES 8 | RUN mkdir -p /etc/colab /etc/colab/settings.d /etc/colab/plugins.d \ 9 | /etc/colab/widgets.d /var/labhacker/colab/public/media \ 10 | /etc/cron.d/ /var/log/colab/ 11 | 12 | ADD . /var/labhacker/colab 13 | WORKDIR /var/labhacker/colab 14 | 15 | RUN pip install . psycopg2 gunicorn elasticsearch python-memcached easy_thumbnails && \ 16 | rm -r /root/.cache 17 | 18 | RUN pip install colab-edemocracia colab-audiencias colab-discourse \ 19 | colab-wikilegis colab-mkdocs-tos 20 | 21 | WORKDIR /usr/lib/python2.7/site-packages/colab_edemocracia 22 | RUN npm install 23 | WORKDIR /var/labhacker/colab 24 | 25 | COPY ./misc/etc/colab/settings.py ./misc/etc/colab/gunicorn.py /etc/colab/ 26 | COPY ./misc/etc/colab/settings.d/01-database.py \ 27 | ./misc/etc/colab/settings.d/02-memcached.py \ 28 | ./misc/etc/colab/settings.d/03-logging.py \ 29 | /etc/colab/settings.d/ 30 | 31 | COPY ./misc/etc/colab/plugins.d/edemocracia.py \ 32 | ./misc/etc/colab/plugins.d/tos.py \ 33 | /etc/colab/plugins.d/ 34 | 35 | RUN npm install -g bower && \ 36 | colab-admin bower_install --allow-root && \ 37 | colab-admin collectstatic --noinput && \ 38 | colab-admin build_mkdocs && \ 39 | colab-admin compilemessages 40 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include MANIFEST.in 3 | recursive-include colab/static * 4 | recursive-include colab/locale * 5 | recursive-include colab/super_archives/locale * 6 | recursive-include colab/proxy/noosfero/static * 7 | recursive-include colab *.html *.txt *.xml 8 | recursive-include misc * 9 | recursive-exclude * __pycache__ 10 | recursive-exclude * *.py[co] 11 | include requirements.txt 12 | -------------------------------------------------------------------------------- /colab/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | # This will make sure the app is always imported when 4 | # Django starts so that shared_task will use this app. 5 | from .celery import app as celery_app # noqa 6 | -------------------------------------------------------------------------------- /colab/accounts/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | default_app_config = 'colab.accounts.apps.AccountsConfig' 3 | -------------------------------------------------------------------------------- /colab/accounts/admin.py: -------------------------------------------------------------------------------- 1 | 2 | from django.contrib import admin 3 | from django.contrib.auth import get_user_model 4 | from django.contrib.auth.admin import UserAdmin 5 | from django.utils.translation import ugettext_lazy as _ 6 | 7 | from .forms import ColabSetUsernameForm, UserChangeForm 8 | 9 | User = get_user_model() 10 | 11 | 12 | class CustomUserAdmin(UserAdmin): 13 | form = UserChangeForm 14 | add_form = ColabSetUsernameForm 15 | 16 | fieldsets = ( 17 | (None, {'fields': ('username', 'email', 'password')}), 18 | (_('Personal info'), {'fields': ('first_name', 19 | 'last_name', 20 | 'twitter', 21 | 'facebook', 22 | 'google_talk', 23 | 'webpage')}), 24 | (_('Permissions'), {'fields': ('is_active', 25 | 'is_staff', 26 | 'is_superuser', 27 | 'groups')}), 28 | (_('Important dates'), {'fields': ('last_login', 'date_joined')}) 29 | ) 30 | 31 | add_fieldsets = ( 32 | (None, { 33 | 'classes': ('wide',), 34 | 'fields': ('username', 'first_name', 'last_name', 35 | 'email', 'password1', 'password2'), 36 | }), 37 | ) 38 | list_display = ( 39 | 'username', 'email', 'date_joined', 'last_login', 'is_active') 40 | list_filter = ('last_login', 'date_joined', 'is_active') 41 | 42 | 43 | admin.site.register(User, CustomUserAdmin) 44 | -------------------------------------------------------------------------------- /colab/accounts/apps.py: -------------------------------------------------------------------------------- 1 | 2 | from django.apps import AppConfig 3 | 4 | 5 | class AccountsConfig(AppConfig): 6 | name = 'colab.accounts' 7 | -------------------------------------------------------------------------------- /colab/accounts/backends.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from django.contrib.auth.backends import ModelBackend 3 | from django.db.models import Q 4 | 5 | 6 | class UsernameOrEmailBackend(ModelBackend): 7 | 8 | def authenticate(self, username=None, password=None): 9 | user_model = get_user_model() 10 | try: 11 | user = user_model.objects.get( 12 | Q(username=username) | Q(email=username) 13 | ) 14 | if user.check_password(password): 15 | return user 16 | except user_model.DoesNotExist: 17 | return None 18 | except: 19 | return None 20 | -------------------------------------------------------------------------------- /colab/accounts/context_processors.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.urlresolvers import reverse 3 | 4 | 5 | def social_network_enabled(request): 6 | return {'SOCIAL_NETWORK_ENABLED': getattr(settings, 7 | 'SOCIAL_NETWORK_ENABLED', 8 | False)} 9 | 10 | 11 | def redirect_login(request): 12 | previous_path = request.COOKIES.get('_previous_path') 13 | if previous_path is None: 14 | return {'previous_path': reverse('home')} 15 | else: 16 | return {'previous_path': previous_path} 17 | -------------------------------------------------------------------------------- /colab/accounts/filters.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext as _ 2 | 3 | 4 | def get_filters(request): 5 | return { 6 | 'user': { 7 | 'name': _(u'User'), 8 | 'icon': 'user', 9 | 'fields': ( 10 | ( 11 | 'username', 12 | _(u'Username'), 13 | request.get('username'), 14 | ), 15 | ('name', _(u'Name'), request.get('name')), 16 | ( 17 | 'institution', 18 | _(u'Institution'), 19 | request.get('institution'), 20 | ), 21 | ('role', _(u'Role'), request.get('role')) 22 | ), 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /colab/accounts/migrations/0002_user_needs_update.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('accounts', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='user', 16 | name='needs_update', 17 | field=models.BooleanField(default=False), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /colab/accounts/migrations/0003_auto_20141218_1755.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('accounts', '0002_user_needs_update'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='user', 16 | name='needs_update', 17 | field=models.BooleanField(default=True), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /colab/accounts/migrations/0004_auto_20150311_1818.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | def trim_fields(apps, schema_editor): 7 | trim_extra_account(apps, schema_editor, "facebook") 8 | trim_extra_account(apps, schema_editor, "github") 9 | trim_extra_account(apps, schema_editor, "twitter") 10 | 11 | def trim_extra_account(apps, schema_editor, types): 12 | Users = apps.get_model('accounts', 'User') 13 | for user in Users.objects.all(): 14 | field = getattr(user, types) 15 | if not field: 16 | continue 17 | tmpString = field.split("/")[-1] 18 | if len(field) >= 15: 19 | setattr(user, types, tmpString[:14]) 20 | user.save() 21 | 22 | 23 | class Migration(migrations.Migration): 24 | 25 | dependencies = [ 26 | ('accounts', '0003_auto_20141218_1755'), 27 | ] 28 | 29 | operations = [ 30 | migrations.RunPython(trim_fields), 31 | migrations.AlterField( 32 | model_name='user', 33 | name='facebook', 34 | field=models.CharField(max_length=15, null=True, blank=True), 35 | preserve_default=True, 36 | ), 37 | 38 | migrations.AlterField( 39 | model_name='user', 40 | name='github', 41 | field=models.CharField(max_length=39, null=True, verbose_name='github', blank=True), 42 | preserve_default=True, 43 | ), 44 | migrations.AlterField( 45 | model_name='user', 46 | name='twitter', 47 | field=models.CharField(max_length=15, null=True, blank=True), 48 | preserve_default=True, 49 | ), 50 | ] 51 | -------------------------------------------------------------------------------- /colab/accounts/migrations/0005_auto_20150312_1454.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.contrib.auth.hashers import make_password 5 | from django.db import models, migrations 6 | from django.utils.crypto import get_random_string 7 | 8 | 9 | def normalize_password(apps, schema_editor): 10 | User = apps.get_model("accounts", "User") 11 | for user in User.objects.all(): 12 | if len(user.password) is not 0: 13 | continue 14 | 15 | rand_pwd = get_random_string() 16 | 17 | user.password = make_password(rand_pwd) 18 | user.save() 19 | 20 | 21 | class Migration(migrations.Migration): 22 | 23 | dependencies = [ 24 | ('accounts', '0004_auto_20150311_1818'), 25 | ] 26 | 27 | operations = [ 28 | migrations.RunPython(normalize_password) 29 | ] 30 | -------------------------------------------------------------------------------- /colab/accounts/migrations/0006_auto_20150828_1719.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.core.validators 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('accounts', '0005_auto_20150312_1454'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='user', 17 | name='username', 18 | field=models.CharField(help_text='Required. 30 characters or fewer. Letters and digits.', unique=True, max_length=30, verbose_name='username', validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')]), 19 | preserve_default=True, 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /colab/accounts/migrations/0007_auto_20151105_0120.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import django.db.models.deletion 6 | from django.conf import settings 7 | import colab.accounts.utils.email 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | ('accounts', '0006_auto_20150828_1719'), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='EmailAddress', 19 | fields=[ 20 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 21 | ('address', models.EmailField(unique=True, max_length=75)), 22 | ('real_name', models.CharField(db_index=True, max_length=64, blank=True)), 23 | ('md5', models.CharField(max_length=32, null=True)), 24 | ('user', models.ForeignKey(related_name='emails', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), 25 | ], 26 | options={ 27 | 'ordering': ('id',), 28 | }, 29 | bases=(models.Model,), 30 | ), 31 | migrations.CreateModel( 32 | name='EmailAddressValidation', 33 | fields=[ 34 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 35 | ('address', models.EmailField(unique=True, max_length=75)), 36 | ('validation_key', models.CharField(default=colab.accounts.utils.email.get_validation_key, max_length=32, null=True)), 37 | ('created', models.DateTimeField(auto_now_add=True)), 38 | ('user', models.ForeignKey(related_name='emails_not_validated', to=settings.AUTH_USER_MODEL, null=True)), 39 | ], 40 | options={ 41 | }, 42 | bases=(models.Model,), 43 | ), 44 | migrations.AlterUniqueTogether( 45 | name='emailaddressvalidation', 46 | unique_together=set([('user', 'address')]), 47 | ), 48 | ] 49 | -------------------------------------------------------------------------------- /colab/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /colab/accounts/signals.py: -------------------------------------------------------------------------------- 1 | 2 | from django.dispatch import Signal 3 | 4 | 5 | user_created = Signal(providing_args=['user', 'password']) 6 | user_password_changed = Signal(providing_args=['user', 'password']) 7 | -------------------------------------------------------------------------------- /colab/accounts/tasks.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | 3 | from celery.decorators import periodic_task 4 | from colab.accounts.models import User 5 | from django.conf import settings 6 | from django.utils import timezone 7 | 8 | 9 | @periodic_task(run_every=timedelta(minutes=60)) 10 | def account_verification(): 11 | limit = settings.ACCOUNT_VERIFICATION_TIME 12 | 13 | inactive_users = User.objects.filter(is_active=False) 14 | for user in inactive_users: 15 | delta_time = timezone.now() - user.modified 16 | if delta_time > limit: 17 | user.delete() 18 | -------------------------------------------------------------------------------- /colab/accounts/templates/accounts/emails/email_verification.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans with fullname=user.get_full_name|title username=user.username|lower %} 3 | Hey, we want to verify that you are indeed "{{ fullname }} ({{ username }})". 4 | If that's the case, please follow the link below:{% endblocktrans %} 5 | 6 | {{ SITE_URL }}{% url 'email_view' key %} 7 | 8 | {% blocktrans with username=user.username %} 9 | If you're not {{ username }} or didn't request verification you can ignore this email. 10 | {% endblocktrans %} 11 | 12 | -------------------------------------------------------------------------------- /colab/accounts/templates/accounts/manage_subscriptions.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load i18n gravatar %} 3 | 4 | {% block main-content %} 5 | 6 |

{% blocktrans %}Group Subscriptions{% endblocktrans %}

7 |

{% gravatar user_.email 50 %} {{ user_.get_full_name }} ({{ user_.username }})

8 |
9 | 10 |
11 | {% csrf_token %} 12 | 13 |
14 | {% for email, lists in membership.items %} 15 |
16 |
17 |
18 |

{{ email }}

19 |
20 |
21 | {% for list, checked in lists %} 22 |
23 | 26 |
27 | {% endfor %} 28 |
29 |
30 |
31 | {% endfor %} 32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 | 40 |
41 | 42 |

43 |

44 | 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /colab/accounts/templates/accounts/user_create_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block main-content %} 4 | 5 |

{% trans "Sign up" %}

6 | 7 |
8 | {% if form.errors %} 9 |
10 | {% trans "Please correct the errors below and try again." %} 11 |
12 | {% endif %} 13 |
14 | 15 | 16 |

17 | 18 |

19 | 20 | 67 | 68 | {% endblock %} 69 | -------------------------------------------------------------------------------- /colab/accounts/templates/emails/create_list_confirmation.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans with fullname=user.get_full_name|title password=password listname=listname %} 3 | Hello {{fullname}}, 4 | The list {{listname}} was created. The password is {{password}}. 5 | {% endblocktrans %} 6 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block main-content %} 4 |
5 | {% if form.errors %} 6 | {% if form.errors.items|length == 1 %} 7 |
8 | {% trans "Please correct the error below and try again." %} 9 |
10 | {% else %} 11 |
12 | {% trans "Please correct the errors below and try again." %} 13 |
14 | {% endif %} 15 | {% endif %} 16 | 17 | {% for error in form.non_field_errors %} 18 |
19 | {{ error }} 20 |
21 | {% endfor %} 22 |
23 | 24 | 25 |
26 | 60 | 61 | {% endblock %} 62 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/password_change_form_custom.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block main-content %} 4 | 5 |
6 | {% if form.errors %} 7 |
8 | 9 | {% if form.errors.items|length == 1 %} 10 | {% trans "Please correct the error below and try again." %} 11 | {% else %} 12 | {% trans "Please correct the errors below and try again." %} 13 | {% endif %} 14 | 15 |
16 | {% endif %} 17 |
18 | 19 |
20 | 59 | 60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/password_reset_complete_custom.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block pagetitle %}Password reset complete{% endblock %} 4 | 5 | {% block main-content %} 6 |

Your password has been set. You may go ahead and log in now.

7 |

Log in

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/password_reset_confirm_custom.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block pagetitle %}{% trans "Setting New password" %}{% endblock %} 4 | {% block main-content %} 5 | {% if validlink %} 6 | 7 |
8 | {% if form.errors %} 9 |
10 | 11 | {% if form.errors.items|length == 1 %} 12 | {% trans "Please correct the error below and try again." %} 13 | {% else %} 14 | {% trans "Please correct the errors below and try again." %} 15 | {% endif %} 16 | 17 |
18 | {% endif %} 19 |
20 | 21 |
22 | 56 | {% else %} 57 |

Password reset unsuccessful

58 |

The password reset link was invalid,
59 | possibly because it has already been used.
60 | Please request a new password reset.

61 | {% endif %} 62 | 63 | {% endblock %} 64 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/password_reset_done_custom.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block pagetitle %}Password reset successful{% endblock %} 4 | 5 | {% block main-content %} 6 |

We've e-mailed you instructions for setting your password to the e-mail address you submitted.

7 |

You should be receiving it shortly.

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/password_reset_email_custom.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}. 3 | 4 | Please go to the following page and choose a new password: 5 | {% block reset_link %} 6 | {{ protocol }}://{{ domain }}{% url django.contrib.auth.views.password_reset_confirm uidb64=uid, token=token %} 7 | {% endblock %} 8 | 9 | Your username, in case you've forgotten: {{ user.username }} 10 | 11 | Thanks for using our site! 12 | 13 | The {{ site_name }} team. 14 | 15 | {% endautoescape %} 16 | -------------------------------------------------------------------------------- /colab/accounts/templates/registration/password_reset_form_custom.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block main-content %} 4 | 5 | 6 |
7 | {% if form.errors %} 8 |
9 | {% trans "Please correct the errors below and try again." %} 10 |
11 | {% endif %} 12 |
13 | 14 |
15 | 42 | 43 | {% endblock %} 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /colab/accounts/templates/search/indexes/accounts/user_text.txt: -------------------------------------------------------------------------------- 1 | {{ object.username }} 2 | {{ object.get_full_name }} 3 | {{ object.get_full_name|slugify }} 4 | {{ object.institution }} 5 | {{ object.institution|slugify }} 6 | {{ object.role }} 7 | {{ object.role|slugify }} 8 | -------------------------------------------------------------------------------- /colab/accounts/templates/search/user_search_preview.html: -------------------------------------------------------------------------------- 1 | {% load i18n tz highlight gravatar %} 2 | 3 |
4 | 9 |
10 | 11 | 12 | {% if query %} 13 |

{% highlight result.name with query %}

14 | {% else %} 15 |

{{ result.name|title }}

16 | {% endif %} 17 | 18 |
19 | {% trans "Since" %}: {{ result.date_joined|date:"d F Y" }}
20 | {% trans "Registered in" %}: {% trans "User" %}
21 |
22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /colab/accounts/templates/widgets/collaboration_chart.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | {% trans "Contributions" as type_collabs %} 5 | 6 | {% include "doughnut-chart.html" with chart_data=type_count chart_canvas="collabs" name=type_collabs %} 7 | 8 | 9 |
10 |
11 |
12 |

{% trans "Collaborations by Type" %}

13 |
14 |
15 |
16 |
17 | 18 |

19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /colab/accounts/templates/widgets/latest_contributions.html: -------------------------------------------------------------------------------- 1 | {% load i18n gravatar widgets_tag %} 2 | 3 | 4 |
5 |

{% trans "Latest contributions" %}

6 |
    7 | {% for result in results %} 8 | {% include "message-preview.html" %} 9 | {% empty %} 10 |
  • {% trans "No contributions of this user so far." %}
  • 11 | {% endfor %} 12 |
13 | 14 | {% trans "View more contributions..." %} 15 | 16 |
17 | -------------------------------------------------------------------------------- /colab/accounts/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/accounts/templatetags/__init__.py -------------------------------------------------------------------------------- /colab/accounts/templatetags/gravatar.py: -------------------------------------------------------------------------------- 1 | 2 | from django import template 3 | 4 | from colab.accounts.models import EmailAddress 5 | 6 | 7 | register = template.Library() 8 | 9 | 10 | @register.simple_tag(takes_context=True) 11 | def gravatar(context, email, size=80): 12 | if isinstance(email, basestring): 13 | try: 14 | email = EmailAddress.objects.get(address=email) 15 | except EmailAddress.DoesNotExist: 16 | pass 17 | 18 | email_md5 = getattr(email, 'md5', 'anonymous') 19 | 20 | request = context.get('request') 21 | if getattr(request, 'is_secure'): 22 | protocol = 'https' 23 | else: 24 | protocol = 'http' 25 | 26 | return (u'').format(protocol, email_md5, 28 | size, size, size) 29 | -------------------------------------------------------------------------------- /colab/accounts/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/accounts/tests/__init__.py -------------------------------------------------------------------------------- /colab/accounts/tests/test_context_processor.py: -------------------------------------------------------------------------------- 1 | from mock import Mock 2 | from django.test import TestCase, override_settings 3 | from django.http import HttpRequest 4 | from django.core.urlresolvers import reverse 5 | from colab.accounts.context_processors import redirect_login 6 | from colab.middlewares.redirect_login import RedirectLoginMiddleware 7 | from colab.middlewares.cookie_middleware import CookiePreHandlerMiddleware 8 | 9 | 10 | class ContextProcessorTest(TestCase): 11 | 12 | def setUp(self): 13 | self.request = HttpRequest() 14 | self.middleware = RedirectLoginMiddleware() 15 | 16 | @override_settings(COLAB_APPS_LOGIN_URLS=['/login/url']) 17 | def test_redirect_login_previous_path(self): 18 | user = Mock() 19 | user.is_authenticated.return_value = False 20 | self.request.user = user 21 | self.request.META['HTTP_ACCEPT'] = 'text/html; charset=utf-8' 22 | self.request.path = '/other/url' 23 | CookiePreHandlerMiddleware().process_request(self.request) 24 | self.middleware.process_request(self.request) 25 | self.assertEquals({'previous_path': '/other/url'}, 26 | redirect_login(self.request)) 27 | 28 | def test_redirect_login_home(self): 29 | user = Mock() 30 | user.is_authenticated.return_value = True 31 | self.request.user = user 32 | self.middleware.process_request(self.request) 33 | self.assertEquals({'previous_path': reverse('home')}, 34 | redirect_login(self.request)) 35 | -------------------------------------------------------------------------------- /colab/accounts/tests/test_email_validation.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from mock import patch 4 | 5 | from colab.accounts.models import User 6 | from django.test import TestCase, Client 7 | from colab.accounts.models import EmailAddressValidation, EmailAddress 8 | 9 | 10 | class EmailValidationTest(TestCase): 11 | 12 | fixtures = ['test_user.json'] 13 | 14 | def setUp(self): 15 | self.client = Client() 16 | 17 | def authenticate_user(self): 18 | self.client.login(username='chucknorris', password='123colab4') 19 | 20 | @patch('colab.accounts.views.send_verification_email', 21 | return_value="") 22 | def test_send_verification_email_successfuly(self, 23 | mock_send_verification_email): 24 | user = User.objects.get(username='chucknorris') 25 | 26 | EmailAddressValidation.create(user.email, user) 27 | 28 | email_addr, created = EmailAddress.objects.get_or_create( 29 | address=user.email) 30 | email_addr.user = user 31 | email_addr.save() 32 | 33 | self.authenticate_user() 34 | 35 | response = self.client.post('/account/manage/email/validate/', 36 | {'user': user.id, 'email': user.email}) 37 | 38 | self.assertEqual(response.status_code, 204) 39 | self.assertTrue(mock_send_verification_email.called) 40 | 41 | @patch('colab.accounts.views.send_verification_email', 42 | return_value="") 43 | def test_send_verification_email_with_not_verified_email( 44 | self, send_verification_email): 45 | self.authenticate_user() 46 | 47 | user = User.objects.get(username='chucknorris') 48 | 49 | response = self.client.post('/account/manage/email/validate/', 50 | { 51 | 'user': user.id, 52 | 'email': "email@mail.com", 53 | }) 54 | 55 | self.assertEqual(response.status_code, 404) 56 | self.assertFalse(send_verification_email.called) 57 | 58 | @patch('colab.accounts.views.send_verification_email', 59 | return_value="") 60 | def test_send_verification_email_with_not_valid_user_id( 61 | self, send_verification_email): 62 | self.authenticate_user() 63 | 64 | user = User.objects.get(username='chucknorris') 65 | 66 | response = self.client.post('/account/manage/email/validate/', 67 | {'user': len(User.objects.all()) + 1, 68 | 'email': user.email}) 69 | 70 | self.assertEqual(response.status_code, 404) 71 | self.assertFalse(send_verification_email.called) 72 | -------------------------------------------------------------------------------- /colab/accounts/tests/test_tasks.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | from time import sleep 3 | 4 | from colab.accounts.models import User 5 | from colab.accounts.tasks import account_verification 6 | from django.test import TestCase, override_settings 7 | 8 | 9 | class TasksTest(TestCase): 10 | 11 | def create_user(self, name='samplename', email='test@email.com', 12 | is_active=True): 13 | user = User() 14 | user.username = name 15 | user.email = email 16 | user.is_active = is_active 17 | user.save() 18 | 19 | @override_settings(ACCOUNT_VERIFICATION_TIME=timedelta(seconds=1)) 20 | def test_account_verification(self): 21 | self.create_user(name='active_user', email='active_user@email.com') 22 | self.create_user(name='inactive_user', email='inactive@email.com', 23 | is_active=False) 24 | sleep(5) 25 | account_verification() 26 | self.assertEqual(1, User.objects.count()) 27 | self.assertEqual(0, User.objects.filter(is_active=False).count()) 28 | -------------------------------------------------------------------------------- /colab/accounts/tests/test_utils_validators.py: -------------------------------------------------------------------------------- 1 | import urllib2 2 | from mock import patch, Mock 3 | 4 | from django.test import TestCase 5 | 6 | from ..utils.validators import validate_social_account 7 | 8 | 9 | class TestValidators(TestCase): 10 | 11 | @patch('urllib2.urlopen', 12 | side_effect=urllib2.HTTPError(500, "test", 1, 2, None)) 13 | def test_validate_social_account_with_fake_account(self, urlopen_mock): 14 | self.assertFalse(validate_social_account('john-fake', 15 | 'http://twitter.com')) 16 | 17 | @patch('urllib2.urlopen', return_value=Mock(code=200)) 18 | def test_validate_social_account(self, urlopen_mock): 19 | self.assertTrue(validate_social_account('john', 'http://twitter.com')) 20 | -------------------------------------------------------------------------------- /colab/accounts/tests/test_view_signup.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test Sign Up view 3 | This test related with accounts/views.py 4 | """ 5 | 6 | from django.test import TestCase, Client 7 | from colab.accounts.models import User 8 | 9 | 10 | class TestSignUpView(TestCase): 11 | 12 | def setUp(self): 13 | self.user = self.create_user_django() 14 | self.client = Client() 15 | 16 | def tearDown(self): 17 | self.user.delete() 18 | 19 | def create_user_django(self): 20 | user = User.objects.create_user("USERtestCoLaB", 21 | "usertest@colab.com.br", "123colab4") 22 | return user 23 | 24 | def test_user_authenticated_and_unregistered(self): 25 | self.client.login(username="usertestcolab", password="123colab4") 26 | response = self.client.get("/account/register/") 27 | self.assertEquals(200, response.status_code) 28 | self.client.logout() 29 | 30 | def test_user_authenticated_and_registered(self): 31 | self.user.needs_update = False 32 | self.user.save() 33 | self.client.login(username="usertestcolab", password="123colab4") 34 | response = self.client.get("/account/register/") 35 | self.assertEquals(302, response.status_code) 36 | url = "http://testserver/account/usertestcolab" 37 | self.assertEquals(url, response.url) 38 | self.client.logout() 39 | -------------------------------------------------------------------------------- /colab/accounts/tests/utils.py: -------------------------------------------------------------------------------- 1 | from django.forms import ValidationError 2 | 3 | 4 | def password_validator(password): 5 | raise ValidationError('Test error') 6 | 7 | 8 | def username_validator(username): 9 | raise ValidationError('Test error') 10 | -------------------------------------------------------------------------------- /colab/accounts/urls.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf.urls import patterns, url, include 3 | from django.conf import settings 4 | from django.contrib.auth import views as auth_views 5 | 6 | from colab.accounts.views import (UserProfileDetailView, UserProfileUpdateView, 7 | EmailValidationView, EmailView) 8 | 9 | from colab.accounts.forms import (ColabSetPasswordForm, 10 | ColabPasswordChangeForm) 11 | 12 | urlpatterns = patterns('', 13 | url(r'^login/?$', 'django.contrib.auth.views.login', 14 | {'redirect_field_name': 'previous_path'}, name='login'), 15 | 16 | url(r'^logout/?$', 'django.contrib.auth.views.logout', 17 | {'next_page': 'home'}, name='logout'), 18 | 19 | url(r'^password-reset-done/?$', 'colab.accounts.views.password_reset_done_custom', 20 | name="password_reset_done"), 21 | 22 | url(r'^password-reset-complete/$', 'colab.accounts.views.password_reset_complete_custom', 23 | name="password_reset_complete"), 24 | 25 | url(r'^password-reset-confirm/(?P[0-9A-Za-z]+)-(?P.+)/$', 26 | auth_views.password_reset_confirm, 27 | {'template_name': 'registration/password_reset_confirm_custom.html', 28 | 'set_password_form': ColabSetPasswordForm}, 29 | name="password_reset_confirm"), 30 | 31 | url(r'^password-reset/?$', auth_views.password_reset, 32 | {'template_name': 'registration/password_reset_form_custom.html'}, 33 | name="password_reset"), 34 | 35 | url(r'^change-password/?$', auth_views.password_change, 36 | {'template_name': 'registration/password_change_form_custom.html', 37 | 'password_change_form': ColabPasswordChangeForm}, 38 | name='password_change'), 39 | 40 | url(r'^change-password-done/?$', 41 | 'colab.accounts.views.password_changed', name='password_change_done'), 42 | ) 43 | 44 | urlpatterns += patterns('', 45 | url(r'^register/?$', 'colab.accounts.views.signup', name='signup'), 46 | 47 | url(r'^social/', include('social.apps.django_app.urls', 48 | namespace=settings.SOCIAL_AUTH_URL_NAMESPACE)), 49 | 50 | url(r'^(?P[\w@+.-]+)/?$', 51 | UserProfileDetailView.as_view(), name='user_profile'), 52 | 53 | url(r'^(?P[\w@+.-]+)/edit/?$', 54 | UserProfileUpdateView.as_view(), name='user_profile_update'), 55 | 56 | url(r'^manage/email/validate/?$', EmailValidationView.as_view(), 57 | name="email_validation_view"), 58 | 59 | url(r'^manage/email/(?P[0-9a-z]{32})?', EmailView.as_view(), 60 | name="email_view"), 61 | ) 62 | -------------------------------------------------------------------------------- /colab/accounts/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/accounts/utils/__init__.py -------------------------------------------------------------------------------- /colab/accounts/utils/email.py: -------------------------------------------------------------------------------- 1 | 2 | from uuid import uuid4 3 | 4 | from django.core import mail 5 | from django.conf import settings 6 | from django.template import Context, loader 7 | from django.utils.translation import ugettext as _ 8 | 9 | 10 | def get_validation_key(): 11 | return uuid4().hex 12 | 13 | 14 | def colab_send_email(subject, message, to): 15 | from_email = settings.COLAB_FROM_ADDRESS 16 | return mail.send_mail(subject, message, from_email, [to]) 17 | 18 | 19 | def send_verification_email(to, user, validation_key, site_url=None): 20 | subject = _('Please verify your email ') + u'{}'.format(to) 21 | msg_tmpl = \ 22 | loader.get_template('accounts/emails/email_verification.txt') 23 | if not site_url: 24 | site_url = getattr(settings, "SITE_URL", "localhost") 25 | message = msg_tmpl.render(Context({'to': to, 'user': user, 26 | 'key': validation_key, 27 | 'SITE_URL': site_url})) 28 | return colab_send_email(subject, message, to) 29 | -------------------------------------------------------------------------------- /colab/accounts/utils/validators.py: -------------------------------------------------------------------------------- 1 | 2 | import urllib2 3 | import urlparse 4 | 5 | 6 | def validate_social_account(account, url): 7 | """Verifies if a social account is valid. 8 | 9 | Examples: 10 | 11 | >>> validate_social_account('seocam', 'http://twitter.com') 12 | True 13 | 14 | >>> validate_social_account('seocam-fake-should-fail', 15 | 'http://twitter.com') 16 | False 17 | 18 | """ 19 | 20 | request = urllib2.Request(urlparse.urljoin(url, account)) 21 | request.get_method = lambda: 'HEAD' 22 | 23 | try: 24 | response = urllib2.urlopen(request) 25 | except urllib2.HTTPError: 26 | return False 27 | 28 | return response.code == 200 29 | -------------------------------------------------------------------------------- /colab/accounts/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/accounts/widgets/__init__.py -------------------------------------------------------------------------------- /colab/accounts/widgets/collaboration_chart.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import Widget 2 | 3 | 4 | class CollaborationChart(Widget): 5 | name = "collaboration_chart" 6 | template = 'widgets/collaboration_chart.html' 7 | -------------------------------------------------------------------------------- /colab/accounts/widgets/latest_contributions.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import Widget 2 | from colab.plugins.utils.collaborations import get_collaboration_data 3 | 4 | 5 | class LatestContributionsWidget(Widget): 6 | name = 'latest contributionsp' 7 | template = 'widgets/latest_contributions.html' 8 | 9 | def generate_content(self, **kwargs): 10 | collaborations, count_types_extras = get_collaboration_data( 11 | kwargs['context']['user'], kwargs['context']['object']) 12 | 13 | collaborations.sort(key=lambda elem: elem.modified, reverse=True) 14 | kwargs['context']['results'] = collaborations[:10] 15 | 16 | super(LatestContributionsWidget, self).generate_content(**kwargs) 17 | -------------------------------------------------------------------------------- /colab/celery.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import os 4 | 5 | from celery import Celery 6 | 7 | # set the default Django settings module for the 'celery' program. 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'colab.settings') 9 | 10 | from django.conf import settings # NOQA 11 | 12 | app = Celery('colab') 13 | 14 | app.config_from_object('django.conf:settings') 15 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 16 | 17 | 18 | @app.task(bind=True) 19 | def debug_task(self): 20 | print('Request: {0!r}'.format(self.request)) 21 | -------------------------------------------------------------------------------- /colab/conf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/conf/__init__.py -------------------------------------------------------------------------------- /colab/conf/plugin_template/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | {{ app_name_verbose }} Colab plugin 4 | =================================== 5 | """ 6 | from setuptools import setup, find_packages 7 | 8 | install_requires = ['colab'] 9 | 10 | tests_require = ['mock'] 11 | 12 | 13 | setup( 14 | name="{{ app_name_dash }}", 15 | version='0.1.0', 16 | author='<>', 17 | author_email='<>', 18 | url='<< project url/repo url >>', 19 | description='{{ app_name_verbose }} Colab plugin', 20 | long_description=__doc__, 21 | license='<< project license >>', 22 | package_dir={'': 'src'}, 23 | packages=find_packages('src'), 24 | zip_safe=False, 25 | install_requires=install_requires, 26 | test_suite="tests.runtests.run", 27 | tests_require=tests_require, 28 | extras_require={'test': tests_require}, 29 | include_package_data=True, 30 | classifiers=[ 31 | 'Framework :: Django', 32 | 'Intended Audience :: Developers', 33 | 'Intended Audience :: System Administrators', 34 | 'Operating System :: OS Independent', 35 | 'Topic :: Software Development' 36 | ], 37 | ) 38 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | default_app_config = '{{ app_name }}.apps.PluginAppConfig' 4 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/apps.py: -------------------------------------------------------------------------------- 1 | 2 | from colab.plugins.utils.apps import ColabPluginAppConfig 3 | 4 | 5 | class {{ app_name_camel }}AppConfig(ColabPluginAppConfig): 6 | name = '{{ app_name }}' 7 | verbose_name = '{{ app_name_verbose }} Plugin' 8 | short_name = '{{ app_name }}' 9 | namespace = '{{ app_name }}' 10 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/data_importer.py: -------------------------------------------------------------------------------- 1 | 2 | from colab.plugins.data import PluginDataImporter 3 | 4 | 5 | class {{ app_name_camel }}DataImporter(PluginDataImporter): 6 | app_label = '{{ app_name }}' 7 | 8 | def fetch_data(self): 9 | pass 10 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/diazo.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/models.py: -------------------------------------------------------------------------------- 1 | # Your models here. 2 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/search_indexes.py: -------------------------------------------------------------------------------- 1 | # Your search indexes here. 2 | # See: http://django-haystack.readthedocs.org/en/latest/searchindex_api.html 3 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/urls.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf.urls import patterns, url 3 | 4 | from .views import {{ app_name_camel }}ProxyView 5 | 6 | urlpatterns = patterns('', 7 | url(r'^(?P.*)$', {{ app_name_camel }}ProxyView.as_view(), 8 | name='{{ app_name }}'), 9 | ) 10 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/src/app_name/views.py: -------------------------------------------------------------------------------- 1 | 2 | from colab.plugins.views import ColabProxyView 3 | 4 | 5 | class {{ app_name_camel }}ProxyView(ColabProxyView): 6 | app_label = '{{ app_name }}' 7 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/conf/plugin_template/tests/__init__.py -------------------------------------------------------------------------------- /colab/conf/plugin_template/tests/colab_settings.py: -------------------------------------------------------------------------------- 1 | 2 | ## Set to false in production 3 | DEBUG = True 4 | TEMPLATE_DEBUG = False 5 | 6 | ## System admins 7 | ADMINS = [['John Foo', 'john@example.com'], ['Mary Bar', 'mary@example.com']] 8 | 9 | MANAGERS = ADMINS 10 | 11 | COLAB_FROM_ADDRESS = '"Colab" ' 12 | SERVER_EMAIL = '"Colab" ' 13 | 14 | EMAIL_HOST = 'localhost' 15 | EMAIL_PORT = 25 16 | EMAIL_SUBJECT_PREFIX = '[colab]' 17 | 18 | SECRET_KEY = 'not-a-secret' 19 | 20 | ALLOWED_HOSTS = [ 21 | 'localhost', 22 | # 'example.com', 23 | # 'example.org', 24 | # 'example.net', 25 | ] 26 | 27 | ### Uncomment to enable social networks fields profile 28 | SOCIAL_NETWORK_ENABLED = True 29 | 30 | ## Disable indexing 31 | ROBOTS_NOINDEX = True 32 | 33 | LOGGING = { 34 | 'version': 1, 35 | 36 | 'handlers': { 37 | 'null': { 38 | 'level': 'DEBUG', 39 | 'class': 'logging.NullHandler', 40 | }, 41 | }, 42 | 43 | 'loggers': { 44 | 'colab.mailman': { 45 | 'handlers': ['null'], 46 | 'propagate': False, 47 | }, 48 | 'haystack': { 49 | 'handlers': ['null'], 50 | 'propagate': False, 51 | }, 52 | }, 53 | } 54 | 55 | STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' 56 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/tests/plugins.d/app_name.py: -------------------------------------------------------------------------------- 1 | 2 | from django.utils.translation import ugettext_lazy as _ 3 | from colab.plugins.utils.menu import colab_url_factory 4 | 5 | name = '{{ app_name }}' 6 | verbose_name = '{{ app_name_verbose }} Plugin' 7 | 8 | upstream = 'localhost' 9 | # middlewares = [] 10 | 11 | urls = { 12 | 'include': '{{ app_name }}.urls', 13 | 'prefix': '^{{ app_name }}/', 14 | } 15 | 16 | menu_title = _('{{ app_name }}') 17 | 18 | url = colab_url_factory('{{ app_name }}') 19 | 20 | # Extra data to be exposed to plugin app config 21 | extra = {} 22 | 23 | menu_urls = ( 24 | # Example of menu URL: 25 | # url(display=_('Public Projects'), viewname='{{ app_name }}', 26 | # kwargs={'path': 'public/projects'}, auth=False), 27 | 28 | # Example of authenticated user menu URL: 29 | # url(display=_('Profile'), viewname='{{ app_name }}', 30 | # kwargs={'path': 'profile'}, auth=True), 31 | ) 32 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/tests/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | import django 6 | from django.conf import settings 7 | from django.test.utils import get_runner 8 | 9 | 10 | def run(): 11 | os.environ['DJANGO_SETTINGS_MODULE'] = 'colab.settings' 12 | os.environ['COLAB_PLUGINS'] = 'tests/plugins.d' 13 | os.environ['COLAB_SETTINGS'] = 'tests/colab_settings.py' 14 | django.setup() 15 | TestRunner = get_runner(settings) 16 | test_runner = TestRunner() 17 | failures = test_runner.run_tests(["tests"]) 18 | sys.exit(bool(failures)) 19 | 20 | 21 | if __name__ == "__main__": 22 | run() 23 | -------------------------------------------------------------------------------- /colab/conf/plugin_template/tests/test_plugin.py: -------------------------------------------------------------------------------- 1 | 2 | from django.test import TestCase, Client 3 | 4 | 5 | class {{ app_name_camel }}PluginTest(TestCase): 6 | 7 | def setUp(self): 8 | self.client = Client() 9 | 10 | def test_true(self): 11 | assert True 12 | -------------------------------------------------------------------------------- /colab/exceptions.py: -------------------------------------------------------------------------------- 1 | 2 | class ColabException(Exception): 3 | """Base class for all exceptions raised by Colab""" 4 | -------------------------------------------------------------------------------- /colab/home/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | default_app_config = 'colab.home.apps.HomeConfig' 4 | -------------------------------------------------------------------------------- /colab/home/admin.py: -------------------------------------------------------------------------------- 1 | # uncomment the import if you really use. 2 | # from django.contrib import admin 3 | 4 | # Register your models here. 5 | -------------------------------------------------------------------------------- /colab/home/apps.py: -------------------------------------------------------------------------------- 1 | 2 | from django.apps import AppConfig 3 | 4 | 5 | class HomeConfig(AppConfig): 6 | name = 'colab.home' 7 | -------------------------------------------------------------------------------- /colab/home/context_processors.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | 5 | def robots(request): 6 | return {'ROBOTS_NOINDEX': getattr(settings, 'ROBOTS_NOINDEX', False)} 7 | 8 | 9 | def google_analytics(request): 10 | key = 'GOOGLE_ANALYTICS_TRACKING_ID' 11 | return {key: getattr(settings, key, False)} 12 | 13 | 14 | def ribbon(request): 15 | enabled = getattr(settings, 'RIBBON_ENABLED', True) 16 | if not enabled: 17 | return {'ribbon': False} 18 | 19 | url = 'http://github.com/colab/colab' 20 | text = _('Fork me!') 21 | 22 | return { 23 | 'ribbon': { 24 | 'text': getattr(settings, 'RIBBON_TEXT', text), 25 | 'url': getattr(settings, 'RIBBON_URL', url), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /colab/home/models.py: -------------------------------------------------------------------------------- 1 | # uncomment the import if you really use. 2 | # from django.db import models 3 | 4 | # Create your models here. 5 | -------------------------------------------------------------------------------- /colab/home/tests.py: -------------------------------------------------------------------------------- 1 | # uncomment the import if you really use. 2 | # from django.test import TestCase 3 | 4 | # Create your tests here. 5 | -------------------------------------------------------------------------------- /colab/home/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.shortcuts import render 3 | from django.http import HttpResponse, Http404 4 | 5 | from colab.plugins.utils.collaborations import get_collaboration_data 6 | from colab.accounts.models import User 7 | 8 | 9 | def dashboard(request): 10 | """Dashboard page""" 11 | 12 | user = None 13 | if request.user.is_authenticated(): 14 | user = User.objects.get(username=request.user) 15 | 16 | latest_results, count_types = get_collaboration_data(user) 17 | latest_results.sort(key=lambda elem: elem.modified, reverse=True) 18 | 19 | context = { 20 | 'type_count': count_types, 21 | 'latest_results': latest_results[:6], 22 | } 23 | return render(request, 'home.html', context) 24 | 25 | 26 | def robots(request): 27 | if getattr(settings, 'ROBOTS_NOINDEX', False): 28 | return HttpResponse('User-agent: *\nDisallow: /', 29 | content_type='text/plain') 30 | 31 | raise Http404 32 | -------------------------------------------------------------------------------- /colab/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /colab/locale/pt_BR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/locale/pt_BR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /colab/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/management/__init__.py -------------------------------------------------------------------------------- /colab/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/management/commands/__init__.py -------------------------------------------------------------------------------- /colab/management/commands/celery.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | from celery.bin import celery 4 | 5 | from colab.celery import app 6 | from colab.queue.command import CeleryCommand 7 | 8 | base = celery.CeleryCommand(app=app) 9 | 10 | 11 | # this is a reimplementation of the djcelery 'celery' command 12 | # taken from Sentry 13 | class Command(CeleryCommand): 14 | """The celery command.""" 15 | help = 'celery commands, see celery help' 16 | options = (CeleryCommand.options + base.get_options() + 17 | base.preload_options) 18 | 19 | def run_from_argv(self, argv): 20 | argv = self.handle_default_options(argv) 21 | if self.requires_system_checks: 22 | self.validate() 23 | base.execute_from_commandline( 24 | ['{0[0]} {0[1]}'.format(argv)] + argv[2:], 25 | ) 26 | -------------------------------------------------------------------------------- /colab/management/commands/initdb.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | from django.contrib.auth import get_user_model 3 | from django.contrib.sites.models import Site 4 | import re 5 | import os 6 | import sys 7 | 8 | 9 | User = get_user_model() 10 | 11 | 12 | class Command(BaseCommand): 13 | help = ('Create admin and set site domain') 14 | 15 | def handle(self, *args, **kwargs): 16 | self.set_site_domain() 17 | self.create_admin() 18 | 19 | def set_site_domain(self): 20 | site = Site.objects.get_current() 21 | site_domain = os.environ.get('SITE_DOMAIN', None) 22 | site_name = os.environ.get('SITE_NAME', None) 23 | 24 | if None not in [site_domain, site_name]: 25 | print('Updating site infos...') 26 | regex = re.compile('^(http|https)://') 27 | if not regex.findall(site_domain): 28 | site_domain = 'http://' + site_domain 29 | 30 | site.domain, site.name = site_domain, site_name 31 | site.save() 32 | print('Done!') 33 | else: 34 | print('Missing SITE_DOMAIN or SITE_NAME environment variable.') 35 | sys.exit(2) 36 | 37 | def create_admin(self): 38 | admin_email = os.environ.get('ADMIN_EMAIL', None) 39 | admin_username = os.environ.get('ADMIN_USERNAME', None) 40 | admin_passwd = os.environ.get('ADMIN_PASSWORD', None) 41 | 42 | if None not in [admin_email, admin_passwd, admin_username]: 43 | print('Creating superuser...') 44 | user = User.objects.get_or_create(email=admin_email, 45 | username=admin_username)[0] 46 | user.set_password(admin_passwd) 47 | user.is_superuser = True 48 | user.is_staff = True 49 | user.save() 50 | print('Done!') 51 | else: 52 | print('Missing ADMIN_EMAIL, ADMIN_USERNAME or ADMIN_PASSWORD ' 53 | 'environment variable.') 54 | sys.exit(1) 55 | -------------------------------------------------------------------------------- /colab/management/commands/initwidgetsconfig.py: -------------------------------------------------------------------------------- 1 | from django.core.management.base import BaseCommand 2 | 3 | 4 | CONFIG_TEMPLATE = r""" 5 | from colab.widgets.widget_manager import WidgetManager 6 | 7 | from colab.widgets.dashboard.dashboard_latest_collaborations import \ 8 | DashboardLatestCollaborationsWidget 9 | from colab.widgets.dashboard.dashboard_collaboration_graph import \ 10 | DashboardCollaborationGraphWidget 11 | 12 | from colab.accounts.widgets.group import GroupWidget 13 | from colab.accounts.widgets.group_membership import GroupMembershipWidget 14 | from colab.accounts.widgets.latest_posted import LatestPostedWidget 15 | from colab.accounts.widgets.latest_contributions import \ 16 | LatestContributionsWidget 17 | 18 | from colab.accounts.widgets.collaboration_chart import CollaborationChart 19 | from colab.accounts.widgets.participation_chart import ParticipationChart 20 | 21 | # Dashboard Widgets 22 | WidgetManager.register_widget('dashboard', 23 | DashboardLatestCollaborationsWidget()) 24 | WidgetManager.register_widget('dashboard', 25 | DashboardCollaborationGraphWidget()) 26 | """ 27 | 28 | 29 | class Command(BaseCommand): 30 | help = ('Returns the default widget configuration, ' 31 | 'including the core widgets.') 32 | 33 | def handle(self, *args, **kwargs): 34 | print(CONFIG_TEMPLATE) 35 | -------------------------------------------------------------------------------- /colab/management/commands/startplugin.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | import colab 5 | 6 | from django.core.management.commands.startapp import Command as StartAppCommand 7 | from django.core.management.base import CommandError 8 | 9 | 10 | class Command(StartAppCommand): 11 | help = ("Creates a Colab plugin directory structure for the given " 12 | "plugin name in the current directory or optionally in the " 13 | "plugin directory.") 14 | missing_args_message = "You must provide a plugin name" 15 | 16 | def handle_template(self, template, subdir): 17 | return os.path.join(colab.__path__[0], 'conf', 'plugin_template') 18 | 19 | def handle(self, app_name=None, target=None, **options): 20 | if app_name is None or app_name == "": 21 | # XXX: remove this when update django to 1.8 or higher 22 | raise CommandError(self.missing_args_message) 23 | 24 | options['app_name_dash'] = app_name.replace('_', '-') 25 | options['app_name_camel'] = app_name.title().replace('_', '') 26 | options['app_name_verbose'] = app_name.replace('_', ' ').title() 27 | 28 | super(Command, self).handle(app_name, target, **options) 29 | -------------------------------------------------------------------------------- /colab/management/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/management/tests/__init__.py -------------------------------------------------------------------------------- /colab/management/tests/test_celery_command.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | 3 | from django.test import TestCase 4 | 5 | from colab.management.commands.celery import Command 6 | 7 | 8 | class CeleryCommandTest(TestCase): 9 | 10 | @patch.object(Command, 'validate') 11 | @patch('colab.management.commands.celery.base.execute_from_commandline') 12 | def test_run_from_argv(self, execute_from_commandline_mock, validate_mock): 13 | cmd = Command() 14 | cmd.requires_system_checks = True 15 | 16 | cmd.run_from_argv(["arg1", "arg2", "arg3"]) 17 | 18 | self.assertTrue(validate_mock.called) 19 | self.assertTrue(execute_from_commandline_mock.called) 20 | -------------------------------------------------------------------------------- /colab/management/tests/test_initconfig_command.py: -------------------------------------------------------------------------------- 1 | from StringIO import StringIO 2 | from mock import patch 3 | 4 | from django.test import TestCase 5 | 6 | from colab.management.commands.initconfig import Command 7 | 8 | 9 | class InitConfigCommandTest(TestCase): 10 | 11 | @patch('sys.stdout', new_callable=StringIO) 12 | def test_initconfig_command(self, stdout_mock): 13 | cmd = Command() 14 | cmd.handle() 15 | 16 | self.assertIn('DEBUG', stdout_mock.getvalue()) 17 | self.assertIn('SECRET_KEY', stdout_mock.getvalue()) 18 | self.assertIn('MANAGERS', stdout_mock.getvalue()) 19 | self.assertIn('LOGGING', stdout_mock.getvalue()) 20 | self.assertNotIn('AVOCADO', stdout_mock.getvalue()) 21 | -------------------------------------------------------------------------------- /colab/middlewares/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/middlewares/__init__.py -------------------------------------------------------------------------------- /colab/middlewares/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/middlewares/models.py -------------------------------------------------------------------------------- /colab/middlewares/redirect_login.py: -------------------------------------------------------------------------------- 1 | from django.utils import timezone 2 | from datetime import timedelta 3 | from django.core.urlresolvers import reverse 4 | from django.conf import settings 5 | 6 | 7 | class RedirectLoginMiddleware(object): 8 | 9 | def process_request(self, request): 10 | if request.user.is_authenticated(): 11 | return 12 | 13 | if request.is_ajax(): 14 | return 15 | 16 | if request.path == reverse('login'): 17 | return 18 | 19 | if 'text/html' in request.META.get('HTTP_ACCEPT', ''): 20 | if request.path not in settings.COLAB_APPS_LOGIN_URLS: 21 | cookie_expire = timezone.now() + timedelta(minutes=1) 22 | request.COOKIES.set('_previous_path', value=request.path, 23 | expires=cookie_expire, max_age=10) 24 | -------------------------------------------------------------------------------- /colab/middlewares/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/middlewares/tests/__init__.py -------------------------------------------------------------------------------- /colab/middlewares/tests/test_redirect_login.py: -------------------------------------------------------------------------------- 1 | from mock import Mock 2 | from django.test import TestCase, override_settings 3 | from django.http import HttpRequest 4 | from colab.accounts.models import User 5 | from colab.middlewares.redirect_login import RedirectLoginMiddleware 6 | from colab.middlewares.cookie_middleware import CookiePreHandlerMiddleware 7 | 8 | 9 | class RedirectLoginTest(TestCase): 10 | 11 | def setUp(self): 12 | self.request = HttpRequest() 13 | self.middleware = RedirectLoginMiddleware() 14 | 15 | def create_user(self): 16 | user = User() 17 | user.username = "USERtestCoLaB" 18 | user.set_password("123colab4") 19 | user.email = "usertest@colab.com.br" 20 | user.id = 1 21 | user.twitter = "usertestcolab" 22 | user.facebook = "usertestcolab" 23 | user.first_name = "USERtestCoLaB" 24 | user.last_name = "COLAB" 25 | user.save() 26 | 27 | return user 28 | 29 | def test_authenticated_user(self): 30 | user = self.create_user() 31 | self.request.user = user 32 | request = self.middleware.process_request(self.request) 33 | self.assertIsNone(request) 34 | 35 | def test_is_ajax(self): 36 | user = Mock() 37 | user.is_authenticated.return_value = False 38 | self.request.user = user 39 | self.request.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' 40 | request = self.middleware.process_request(self.request) 41 | self.assertIsNone(request) 42 | 43 | def test_image_request(self): 44 | user = Mock() 45 | user.is_authenticated.return_value = False 46 | self.request.user = user 47 | self.request.META['HTTP_ACCEPT'] = 'image/webp,image/*,*/*;q=0.8' 48 | request = self.middleware.process_request(self.request) 49 | self.assertIsNone(request) 50 | 51 | @override_settings(COLAB_APPS_LOGIN_URLS=['/login/url']) 52 | def test_previous_path(self): 53 | user = Mock() 54 | user.is_authenticated.return_value = False 55 | self.request.user = user 56 | self.request.META['HTTP_ACCEPT'] = 'text/html; charset=utf-8' 57 | self.request.path = '/other/url' 58 | CookiePreHandlerMiddleware().process_request(self.request) 59 | self.middleware.process_request(self.request) 60 | self.assertEquals('/other/url', 61 | self.request.COOKIES.get('_previous_path')) 62 | -------------------------------------------------------------------------------- /colab/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | default_app_config = 'colab.plugins.apps.PluginAppConfig' 3 | -------------------------------------------------------------------------------- /colab/plugins/apps.py: -------------------------------------------------------------------------------- 1 | 2 | from django.apps import AppConfig 3 | 4 | from .data import register_tasks 5 | from .utils.signals import connect_signal, register_signal 6 | 7 | 8 | class PluginAppConfig(AppConfig): 9 | name = 'colab.plugins' 10 | 11 | def ready(self): 12 | register_signal() 13 | connect_signal() 14 | 15 | register_tasks() 16 | -------------------------------------------------------------------------------- /colab/plugins/conf.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf import settings 3 | 4 | 5 | def get_plugin_config(app_label): 6 | return settings.COLAB_APPS.get(app_label, {}) 7 | -------------------------------------------------------------------------------- /colab/plugins/context_processors.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | import re 3 | 4 | 5 | def colab_apps(request): 6 | colab_apps = {} 7 | 8 | for app_name, app in settings.COLAB_APPS.items(): 9 | colab_apps[app_name] = app 10 | 11 | return {'plugins': colab_apps} 12 | 13 | 14 | def get_prefixes(): 15 | prefixes = [] 16 | for plugin_name in settings.COLAB_APPS: 17 | plugin = settings.COLAB_APPS[plugin_name] 18 | prefix = plugin['urls']['prefix'] 19 | change_header = plugin.get('change_header', False) 20 | if change_header: 21 | prefixes.append(prefix) 22 | return prefixes 23 | 24 | 25 | def change_header(request): 26 | for prefix in get_prefixes(): 27 | if re.match(prefix, request.path[1:]): 28 | return {'change_header': True} 29 | return {'change_header': False} 30 | -------------------------------------------------------------------------------- /colab/plugins/data/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .base_importer import PluginDataImporter # noqa 3 | from .tasks import TASKS, data_import, register_tasks # noqa 4 | -------------------------------------------------------------------------------- /colab/plugins/data/base_importer.py: -------------------------------------------------------------------------------- 1 | 2 | import abc 3 | 4 | from django.conf import settings 5 | 6 | 7 | class PluginDataImporter(object): 8 | 9 | def __init__(self): 10 | self.config = settings.COLAB_APPS.get(self.app_label, {}) 11 | 12 | @abc.abstractmethod 13 | def fetch_data(self): 14 | raise NotImplementedError 15 | fetch_data.is_abstract = True 16 | 17 | @abc.abstractmethod 18 | def app_label(self): 19 | raise NotImplementedError 20 | -------------------------------------------------------------------------------- /colab/plugins/data/tasks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import importlib 4 | import logging 5 | 6 | from django.conf import settings 7 | 8 | from colab.celery import app 9 | 10 | LOGGER = logging.getLogger('colab.plugins.data') 11 | TASKS = set() 12 | 13 | 14 | def lock(method, name): 15 | def wrapped_method(self, *args, **kwargs): 16 | lock_id = 'colab-data-importer-{}'.format(name) 17 | lock = app.backend.client.lock(lock_id) 18 | 19 | if lock.acquire(blocking=False): 20 | try: 21 | return method(*args, **kwargs) 22 | finally: 23 | lock.release() 24 | 25 | return wrapped_method 26 | 27 | 28 | def register_tasks(): 29 | 30 | global TASKS 31 | 32 | for app_name in settings.INSTALLED_APPS: 33 | 34 | module_name = '{}.data_importer'.format(app_name) 35 | try: 36 | module = importlib.import_module(module_name) 37 | except ImportError: 38 | continue 39 | 40 | for item_name in dir(module): 41 | item = getattr(module, item_name) 42 | 43 | if callable(getattr(item, 'fetch_data', None)): 44 | if getattr(item.fetch_data, 'is_abstract', False): 45 | continue 46 | instance = item() 47 | task_name = '{}.{}'.format(module.__name__, item_name) 48 | thread_safe_method = lock(instance.fetch_data, task_name) 49 | task = app.task(name=task_name, bind=True)(thread_safe_method) 50 | TASKS.add(task) 51 | LOGGER.debug('Registered task: %s', task_name) 52 | 53 | LOGGER.debug(TASKS) 54 | return TASKS 55 | 56 | 57 | def data_import(self): 58 | for task in TASKS: 59 | task.delay() 60 | -------------------------------------------------------------------------------- /colab/plugins/exceptions.py: -------------------------------------------------------------------------------- 1 | class PluginDoesNotExistError(KeyError): 2 | def __init__(self, message): 3 | super(KeyError, self).__init__(message) 4 | -------------------------------------------------------------------------------- /colab/plugins/fixtures/sample_user_plugin.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "fields": { 4 | "last_name": "Administrator", 5 | "webpage": "", 6 | "twitter": "", 7 | "is_staff": true, 8 | "user_permissions": [], 9 | "date_joined": "2015-01-28T12:34:58.770Z", 10 | "google_talk": "", 11 | "first_name": "Admin", 12 | "is_superuser": true, 13 | "last_login": "2016-01-06T19:27:43.553Z", 14 | "verification_hash": null, 15 | "role": "", 16 | "email": "admin@mail.com", 17 | "username": "admin", 18 | "bio": "", 19 | "needs_update": true, 20 | "is_active": true, 21 | "facebook": "", 22 | "groups": [], 23 | "password": "", 24 | "institution": "", 25 | "github": "", 26 | "modified": "2015-01-28T12:45:27.375Z" 27 | }, 28 | "model": "accounts.user", 29 | "pk": 1 30 | }, 31 | { 32 | "fields": { 33 | "last_name": "LastName", 34 | "webpage": "", 35 | "twitter": "", 36 | "is_staff": false, 37 | "user_permissions": [], 38 | "date_joined": "2016-01-06T19:26:59Z", 39 | "google_talk": "", 40 | "first_name": "SampleUser", 41 | "is_superuser": false, 42 | "last_login": "2016-01-06T19:52:50.879Z", 43 | "verification_hash": null, 44 | "role": null, 45 | "email": "sample_user@email.com", 46 | "username": "SampleUser", 47 | "bio": null, 48 | "needs_update": true, 49 | "is_active": true, 50 | "facebook": "", 51 | "groups": [], 52 | "password": "", 53 | "institution": null, 54 | "github": null, 55 | "modified": "2016-01-06T19:27:01.879Z" 56 | }, 57 | "model": "accounts.user", 58 | "pk": 2 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /colab/plugins/helpers.py: -------------------------------------------------------------------------------- 1 | from colab.plugins.exceptions import PluginDoesNotExistError 2 | from django.utils.translation import ugettext as _ 3 | from django.conf import settings 4 | 5 | 6 | def get_plugin_config(plugin_name): 7 | try: 8 | return settings.COLAB_APPS[plugin_name] 9 | except KeyError: 10 | raise PluginDoesNotExistError( 11 | _("Plugin {} does not exist.".format(plugin_name)) 12 | ) 13 | 14 | 15 | def get_plugin_prefix(plugin_name, regex=True): 16 | config = get_plugin_config(plugin_name) 17 | urls = config.get("urls") 18 | prefix = urls.get("prefix") 19 | 20 | if not regex: 21 | prefix = prefix.replace("^", "") 22 | return prefix 23 | -------------------------------------------------------------------------------- /colab/plugins/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | import datetime 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='TimeStampPlugin', 16 | fields=[ 17 | ('id', models.IntegerField(serialize=False, primary_key=True)), 18 | ('name', models.CharField(unique=True, max_length=255)), 19 | ('timestamp', models.DateTimeField(default=datetime.datetime(1, 1, 1, 0, 0), blank=True)), 20 | ], 21 | options={ 22 | }, 23 | bases=(models.Model,), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /colab/plugins/migrations/0002_auto_20160106_1843.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('plugins', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='timestampplugin', 16 | name='id', 17 | field=models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), 18 | preserve_default=True, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /colab/plugins/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/plugins/migrations/__init__.py -------------------------------------------------------------------------------- /colab/plugins/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils import timezone 3 | 4 | 5 | class TimeStampPlugin(models.Model): 6 | ''' 7 | Class used to store timestamps from plugins 8 | ''' 9 | name = models.CharField(max_length=255, unique=True, null=False) 10 | timestamp = models.DateTimeField(default=timezone.datetime.min, blank=True) 11 | 12 | @classmethod 13 | def update_timestamp(cls, class_name, **kwargs): 14 | instance = TimeStampPlugin.objects.get_or_create(name=class_name)[0] 15 | last_updated = kwargs.get('last_updated', '') 16 | 17 | if last_updated: 18 | format = "%Y/%m/%d %H:%M:%S" 19 | instance.timestamp = timezone.datetime.strptime(last_updated, 20 | format) 21 | else: 22 | instance.timestamp = timezone.datetime.now() 23 | instance.save() 24 | 25 | @classmethod 26 | def get_last_updated(cls, class_name): 27 | instance = TimeStampPlugin.objects.get_or_create(name=class_name)[0] 28 | return instance.timestamp 29 | -------------------------------------------------------------------------------- /colab/plugins/tasks.py: -------------------------------------------------------------------------------- 1 | 2 | from datetime import timedelta 3 | from celery.decorators import periodic_task 4 | 5 | from .data import TASKS 6 | 7 | 8 | @periodic_task(run_every=timedelta(seconds=60)) 9 | def import_plugin_data(): 10 | for task in TASKS: 11 | task.delay() 12 | -------------------------------------------------------------------------------- /colab/plugins/templates/plugins/menu_template.html: -------------------------------------------------------------------------------- 1 | {% for title, links in menu_links.items %} 2 | {% if links|length == 1 %} 3 | {% for colab_url in links %} 4 |
  • 5 | {{ title }} 6 |
  • 7 | {% endfor %} 8 | {% else %} 9 | 17 | {% endif %} 18 | {% endfor %} 19 | -------------------------------------------------------------------------------- /colab/plugins/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/plugins/templatetags/__init__.py -------------------------------------------------------------------------------- /colab/plugins/templatetags/plugins.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | from django import template 4 | from django.core.cache import cache 5 | from django.template.loader import render_to_string 6 | from django.utils.translation import get_language 7 | 8 | register = template.Library() 9 | 10 | 11 | @register.simple_tag(takes_context=True) 12 | def plugins_menu(context): 13 | 14 | if context['user'].is_authenticated(): 15 | cache_key = 'colab-plugin-menu-authenticated' 16 | else: 17 | cache_key = 'colab-plugin-menu-anonymous' 18 | 19 | lang = get_language() 20 | cache_key += '-{}'.format(lang) 21 | 22 | menu_from_cache = cache.get(cache_key) 23 | 24 | if menu_from_cache: 25 | return menu_from_cache 26 | 27 | menu_links = OrderedDict() 28 | colab_apps = context.get('plugins', {}) 29 | 30 | for app_name, app in colab_apps.items(): 31 | if not app.get('menu_urls'): 32 | continue 33 | 34 | menu = app.get('menu_urls') 35 | title = app.get('menu_title', app_name) 36 | 37 | if title not in menu_links: 38 | menu_links[title] = [] 39 | 40 | for colab_url in menu: 41 | if not context['user'].is_active and colab_url.auth: 42 | continue 43 | 44 | menu_links[title].append(colab_url) 45 | 46 | if not menu_links[title]: 47 | del menu_links[title] 48 | 49 | menu = render_to_string('plugins/menu_template.html', 50 | {'menu_links': menu_links}) 51 | 52 | cache.set(cache_key, menu) 53 | return menu 54 | -------------------------------------------------------------------------------- /colab/plugins/templatetags/set_var.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | 6 | @register.simple_tag(takes_context=True) 7 | def set(context, var_name, var_value): 8 | context[var_name] = var_value 9 | return "" 10 | -------------------------------------------------------------------------------- /colab/plugins/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/plugins/tests/__init__.py -------------------------------------------------------------------------------- /colab/plugins/tests/test_context_processors.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase, override_settings 2 | from django.http import HttpRequest 3 | from colab.plugins import context_processors 4 | 5 | 6 | class ContextProcessorTest(TestCase): 7 | 8 | def setUp(self): 9 | self.request = HttpRequest() 10 | 11 | @override_settings(COLAB_APPS={'plugin': 'plugin-data'}) 12 | def test_colab_apps(self): 13 | response = context_processors.colab_apps(self.request) 14 | self.assertEqual({'plugins': {'plugin': 'plugin-data'}}, response) 15 | 16 | @override_settings(COLAB_APPS={'plugin': 17 | {'urls': {'prefix': '^plugin/'}, 18 | 'change_header': True}}) 19 | def test_get_prefixes_change_header(self): 20 | prefixes = context_processors.get_prefixes() 21 | self.assertEqual(['^plugin/'], prefixes) 22 | 23 | @override_settings(COLAB_APPS={'plugin': {'urls': {'prefix': '^plugin/'}}}) 24 | def test_get_prefixes_maintain_header(self): 25 | prefixes = context_processors.get_prefixes() 26 | self.assertEqual([], prefixes) 27 | 28 | @override_settings(COLAB_APPS={'plugin': 29 | {'urls': {'prefix': '^plugin/'}, 30 | 'change_header': True}}) 31 | def test_change_header(self): 32 | self.request.path = '/plugin/' 33 | response = context_processors.change_header(self.request) 34 | self.assertEqual({'change_header': True}, response) 35 | 36 | @override_settings(COLAB_APPS={'plugin': 37 | {'urls': {'prefix': '^plugin/'}, 38 | 'change_header': True}}) 39 | def test_change_header_other_url(self): 40 | self.request.path = '/otherurl/' 41 | response = context_processors.change_header(self.request) 42 | self.assertEqual({'change_header': False}, response) 43 | 44 | @override_settings(COLAB_APPS={'plugin': 45 | {'urls': {'prefix': '^plugin/'}, 46 | 'change_header': False}}) 47 | def test_change_header_false(self): 48 | self.request.path = '/plugin/' 49 | response = context_processors.change_header(self.request) 50 | self.assertEqual({'change_header': False}, response) 51 | -------------------------------------------------------------------------------- /colab/plugins/tests/test_helpers.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase, override_settings 2 | from colab.plugins import helpers 3 | from colab.plugins.exceptions import PluginDoesNotExistError 4 | 5 | 6 | class HelpersTest(TestCase): 7 | 8 | @override_settings(COLAB_APPS={'plugin_name': {'plugin': 'infos'}}) 9 | def test_get_plugin_config(self): 10 | self.assertEqual({'plugin': 'infos'}, 11 | helpers.get_plugin_config('plugin_name')) 12 | 13 | @override_settings(COLAB_APPS={'plugin_name': {'plugin': 'infos'}}) 14 | def test_get_plugin_config_not_found(self): 15 | with self.assertRaises(PluginDoesNotExistError): 16 | helpers.get_plugin_config('invalid_name') 17 | 18 | @override_settings(COLAB_APPS={'plugin_name': { 19 | 'urls': {'prefix': '^prefix/'}}}) 20 | def test_get_plugin_prefix(self): 21 | self.assertEqual("^prefix/", 22 | helpers.get_plugin_prefix('plugin_name')) 23 | 24 | @override_settings(COLAB_APPS={'plugin_name': { 25 | 'urls': {'prefix': '^prefix/'}}}) 26 | def test_get_plugin_prefix_no_regex(self): 27 | self.assertEqual("prefix/", 28 | helpers.get_plugin_prefix('plugin_name', regex=False)) 29 | -------------------------------------------------------------------------------- /colab/plugins/tests/test_tasks.py: -------------------------------------------------------------------------------- 1 | from mock import Mock 2 | 3 | from django.test import TestCase 4 | 5 | import colab.plugins.data.tasks 6 | from colab.plugins.tasks import import_plugin_data 7 | 8 | 9 | class TasksTest(TestCase): 10 | 11 | def test_import_plugin_data(self): 12 | task_mock = Mock(delay=Mock()) 13 | 14 | colab.plugins.tasks.TASKS = [task_mock, task_mock, task_mock] 15 | 16 | import_plugin_data() 17 | self.assertEquals(3, task_mock.delay.call_count) 18 | 19 | colab.plugins.tasks.TASKS = [] 20 | -------------------------------------------------------------------------------- /colab/plugins/tests/test_timestamp.py: -------------------------------------------------------------------------------- 1 | import mock 2 | 3 | from django.test import TestCase 4 | from django.utils import timezone 5 | from colab.plugins.models import TimeStampPlugin 6 | 7 | 8 | class UserTest(TestCase): 9 | 10 | def test_update_timestamp_without_last_updated(self): 11 | result = timezone.datetime(2009, 1, 1).replace(tzinfo=timezone.utc) 12 | with mock.patch.object(timezone, 'datetime', 13 | mock.Mock(wraps=timezone.datetime)) as mock_: 14 | mock_.now.return_value = result 15 | TimeStampPlugin.get_last_updated('TestPluginUpdate') 16 | TimeStampPlugin.update_timestamp('TestPluginUpdate') 17 | timestamp = TimeStampPlugin.get_last_updated('TestPluginUpdate') 18 | self.assertEquals(result, timestamp) 19 | 20 | def test_update_timestamp_with_last_updated(self): 21 | date = '2015/12/23 00:00:00' 22 | self.create_sample_timestamp('TestPluginUpdate', date) 23 | timestamp = TimeStampPlugin.get_last_updated('TestPluginUpdate') 24 | self.assertEquals(self.create_timestamp_object(date), timestamp) 25 | 26 | def test_first_get_last_update(self): 27 | timestamp = TimeStampPlugin.get_last_updated('Test') 28 | self.assertEqual(timezone.datetime.min, timestamp) 29 | 30 | def create_sample_timestamp(self, class_name, date): 31 | TimeStampPlugin.get_last_updated(class_name) 32 | TimeStampPlugin.update_timestamp(class_name, last_updated=date) 33 | 34 | def create_timestamp_object(self, date): 35 | return timezone.datetime.strptime(date, "%Y/%m/%d %H:%M:%S")\ 36 | .replace(tzinfo=timezone.utc) 37 | 38 | def test_verify_fields_of_timestamp_plugin(self): 39 | objects = [('TestPluginUpdate', '2015/12/23 00:00:00'), 40 | ('NewPluginUpdate', '2015/09/10 00:00:00'), 41 | ('OldPluginUpdate', '2014/10/01 00:00:00'), 42 | ('ExamplePluginUpdate', '2013/11/03 00:00:00')] 43 | 44 | for object in objects: 45 | self.create_sample_timestamp(object[0], object[1]) 46 | 47 | all_timestamps = TimeStampPlugin.objects.all() 48 | self.assertEqual(len(all_timestamps), 4) 49 | for object in objects: 50 | result = TimeStampPlugin.objects.filter(name=object[0]) 51 | self.assertEqual(object[0], result[0].name) 52 | self.assertEqual(self.create_timestamp_object(object[1]), 53 | result[0].timestamp) 54 | -------------------------------------------------------------------------------- /colab/plugins/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.test.client import RequestFactory 3 | 4 | from ..views import ColabProxyView 5 | from colab.accounts.models import User 6 | 7 | 8 | class ViewsTest(TestCase): 9 | 10 | def setUp(self): 11 | self.view = ColabProxyView() 12 | self.factory = RequestFactory() 13 | self.user = User.objects.create_user( 14 | username='john', email='john@test.org', password='123', 15 | first_name='John', last_name='John') 16 | 17 | def test_dispatch_without_app_label(self): 18 | request = self.factory.get('/') 19 | request.user = self.user 20 | 21 | with self.assertRaises(NotImplementedError): 22 | self.view.dispatch(request, '/') 23 | -------------------------------------------------------------------------------- /colab/plugins/urls.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf import settings 3 | from django.conf.urls import patterns, url, include 4 | from django.core.exceptions import ImproperlyConfigured 5 | 6 | undef_url_include_msg = (u'COLAB_APP with urls must define ' 7 | 'the `include` attribute') 8 | urlpatterns = patterns('') 9 | 10 | for app_name, app in settings.COLAB_APPS.items(): 11 | if not app or 'urls' not in app: 12 | continue 13 | 14 | urls = app.get('urls') 15 | if not urls.get('include'): 16 | raise ImproperlyConfigured(undef_url_include_msg) 17 | urlpatterns += patterns('', 18 | url(urls.get('prefix', r''), include(urls['include'], 19 | namespace=urls.get('namespace'))), 20 | ) 21 | 22 | -------------------------------------------------------------------------------- /colab/plugins/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/plugins/utils/__init__.py -------------------------------------------------------------------------------- /colab/plugins/utils/apps.py: -------------------------------------------------------------------------------- 1 | 2 | from django.apps import AppConfig 3 | from ..conf import get_plugin_config 4 | 5 | 6 | class ColabPluginAppConfig(AppConfig): 7 | colab_proxied_app = True 8 | namespace = None 9 | 10 | def __init__(self, app_name, app_module): 11 | super(ColabPluginAppConfig, self).__init__(app_name, app_module) 12 | self.set_namespace() 13 | 14 | def set_namespace(self): 15 | config = get_plugin_config(self.name) 16 | config['urls']['namespace'] = self.namespace 17 | 18 | def register_signal(self): 19 | pass 20 | 21 | def connect_signal(self): 22 | pass 23 | -------------------------------------------------------------------------------- /colab/plugins/utils/collaborations.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import inspect 3 | 4 | from collections import OrderedDict 5 | 6 | from django.core.cache import cache 7 | from django.conf import settings 8 | 9 | from colab.plugins.utils.models import Collaboration 10 | 11 | 12 | def get_collaboration_data(logged_user, filter_by_user=None): 13 | username = getattr(filter_by_user, 'username', '') 14 | cache_key = 'home_chart-{}'.format(username) 15 | count_types = cache.get(cache_key) 16 | 17 | latest_results = [] 18 | populate_count_types = False 19 | 20 | 21 | if count_types is None: 22 | populate_count_types = True 23 | count_types = OrderedDict() 24 | 25 | for app in settings.COLAB_APPS.values(): 26 | module = importlib.import_module('{}.models'.format(app.get('name'))) 27 | 28 | for module_item_name in dir(module): 29 | module_item = getattr(module, module_item_name) 30 | if not inspect.isclass(module_item): 31 | continue 32 | if not issubclass(module_item, Collaboration): 33 | continue 34 | if module_item == Collaboration: 35 | continue 36 | 37 | queryset = module_item.objects 38 | 39 | if filter_by_user: 40 | elements = queryset.filter( 41 | user__username=filter_by_user) 42 | else: 43 | elements = queryset.all() 44 | 45 | latest_results.extend(elements) 46 | elements_count = elements.count() 47 | 48 | if elements_count > 1: 49 | verbose_name = module_item._meta.verbose_name_plural.title() 50 | else: 51 | verbose_name = module_item._meta.verbose_name.title() 52 | 53 | if populate_count_types: 54 | count_types[verbose_name] = elements_count 55 | 56 | if populate_count_types: 57 | cache.set(cache_key, count_types, 30) 58 | 59 | return latest_results, count_types 60 | -------------------------------------------------------------------------------- /colab/plugins/utils/filters_importer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import importlib 4 | 5 | from django.conf import settings 6 | 7 | 8 | def import_plugin_filters(request): 9 | plugin_filters = {} 10 | for app_name in settings.INSTALLED_APPS: 11 | 12 | module_name = '{}.filters'.format(app_name) 13 | try: 14 | module = importlib.import_module(module_name) 15 | except ImportError: 16 | continue 17 | 18 | get_filters = getattr(module, 'get_filters', None) 19 | if get_filters: 20 | plugin_filters.update(get_filters(request)) 21 | 22 | return plugin_filters 23 | -------------------------------------------------------------------------------- /colab/plugins/utils/menu.py: -------------------------------------------------------------------------------- 1 | from django.core.urlresolvers import reverse_lazy 2 | 3 | 4 | class ColabUrl(object): 5 | def __init__(self, display, url, auth): 6 | self.display = display 7 | self.url = url 8 | self.auth = auth 9 | 10 | 11 | def colab_url_factory(namespace): 12 | 13 | def url(display, viewname, namespace=namespace, args=tuple(), 14 | kwargs={}, auth=False): 15 | 16 | if namespace: 17 | rev_viewname = ':'.join((namespace, viewname)) 18 | else: 19 | rev_viewname = viewname 20 | 21 | url = reverse_lazy(rev_viewname, args=args, kwargs=kwargs) 22 | 23 | return ColabUrl(display, url, auth) 24 | 25 | return url 26 | -------------------------------------------------------------------------------- /colab/plugins/utils/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.conf import settings 3 | from colab.accounts.models import User 4 | 5 | 6 | class Collaboration(models.Model): 7 | ''' 8 | Class to define the fields of the collaboration block 9 | that are displayed at dashboard and profile pages. 10 | ''' 11 | 12 | tag = None 13 | title = None 14 | description = None 15 | url = None 16 | modified = None 17 | type = None 18 | 19 | user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, 20 | on_delete=models.SET_NULL) 21 | 22 | @property 23 | def modified_by(self): 24 | if self.user: 25 | return self.user.get_full_name() 26 | return None 27 | 28 | @property 29 | def modified_by_url(self): 30 | if self.user: 31 | return self.user.get_absolute_url() 32 | return None 33 | 34 | def update_user(self, user_name): 35 | try: 36 | self.user = User.objects.get(username=user_name) 37 | except User.DoesNotExist: 38 | self.user = None 39 | 40 | class Meta: 41 | abstract = True 42 | -------------------------------------------------------------------------------- /colab/plugins/utils/signals.py: -------------------------------------------------------------------------------- 1 | 2 | from django.apps import apps 3 | 4 | 5 | def _init_signals(method_name): 6 | for app in apps.get_app_configs(): 7 | # Try to get the method with `method_name`. 8 | # If it exists call it using `app` as the first parameter. 9 | # This is required because methods take `self` as first 10 | # parameter and as we are calling it as a function python 11 | # won't send it explicitly. 12 | # If the method doesn't exist we return a dummy function that 13 | # won't do anything. 14 | getattr(app, method_name, lambda: None)() 15 | 16 | 17 | def register_signal(): 18 | _init_signals('register_signal') 19 | 20 | 21 | def connect_signal(): 22 | _init_signals('connect_signal') 23 | -------------------------------------------------------------------------------- /colab/plugins/utils/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/plugins/utils/tests/__init__.py -------------------------------------------------------------------------------- /colab/plugins/utils/tests/test_apps.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | 3 | from django.test import TestCase 4 | from django.apps import AppConfig 5 | 6 | from colab.plugins.utils.apps import ColabPluginAppConfig 7 | 8 | 9 | class AppsTest(TestCase): 10 | 11 | @patch.object(AppConfig, '_path_from_module') 12 | @patch('colab.plugins.utils.apps.get_plugin_config') 13 | def test_set_namespace(self, get_plugin_config_mock, 14 | path_from_module_mock): 15 | path_from_module_mock.return_value = "/fake/path" 16 | 17 | get_plugin_config_mock.return_value = {'urls': {}} 18 | conf = get_plugin_config_mock() 19 | 20 | ColabPluginAppConfig("test", "test_app") 21 | 22 | self.assertIn('namespace', conf['urls']) 23 | self.assertEquals(None, conf['urls']['namespace']) 24 | -------------------------------------------------------------------------------- /colab/plugins/utils/tests/test_collaboration.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from colab.accounts.models import User 3 | from colab.plugins.utils.models import Collaboration 4 | 5 | 6 | class CollaborationTest(TestCase): 7 | fixtures = ['sample_user_plugin.json'] 8 | 9 | def setUp(self): 10 | self.collaboration = Collaboration() 11 | 12 | def set_user(self): 13 | sample_user = User.objects.filter(username='SampleUser').last() 14 | self.collaboration.user = sample_user 15 | 16 | def test_modified_by_without_user(self): 17 | self.assertIsNone(self.collaboration.modified_by) 18 | 19 | def test_modified_by_with_valid_user(self): 20 | self.set_user() 21 | self.assertEqual('SampleUser LastName', self.collaboration.modified_by) 22 | 23 | def test_modified_by_url_without_user(self): 24 | self.assertIsNone(self.collaboration.modified_by_url) 25 | 26 | def test_modified_by_url_with_valid_user(self): 27 | self.set_user() 28 | self.assertEquals('/account/SampleUser', 29 | self.collaboration.modified_by_url) 30 | 31 | def test_update_user_without_user(self): 32 | self.collaboration.update_user('SampleInvalidUser') 33 | self.assertIsNone(self.collaboration.user) 34 | 35 | def test_update_user_with_valid_user(self): 36 | self.collaboration.update_user('SampleUser') 37 | self.assertEquals('SampleUser', self.collaboration.user.username) 38 | self.assertEquals('sample_user@email.com', 39 | self.collaboration.user.email) 40 | -------------------------------------------------------------------------------- /colab/plugins/utils/tests/test_signals.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from mock import patch, MagicMock 3 | from colab.plugins.utils import signals 4 | 5 | 6 | class SignalsTest(TestCase): 7 | @patch("colab.plugins.utils.signals.apps.get_app_configs") 8 | def test_init_signals(self, mock_app): 9 | method_name = 'test' 10 | 11 | app_mock = MagicMock() 12 | 13 | apps_list = ['a', 'b', app_mock] 14 | 15 | mock_app.return_value = apps_list 16 | signals._init_signals(method_name) 17 | 18 | app_mock.test.assert_called_with() 19 | self.assertEqual(1, app_mock.test.call_count) 20 | self.assertTrue(app_mock.test.called) 21 | -------------------------------------------------------------------------------- /colab/plugins/views.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | 4 | from django.conf import settings 5 | 6 | from revproxy.views import DiazoProxyView 7 | 8 | from .conf import get_plugin_config 9 | 10 | 11 | class ColabProxyView(DiazoProxyView): 12 | add_remote_user = settings.REVPROXY_ADD_REMOTE_USER 13 | diazo_theme_template = 'base.html' 14 | html5 = True 15 | 16 | @property 17 | def upstream(self): 18 | config = get_plugin_config(self.app_label) 19 | return config.get('upstream') 20 | 21 | @property 22 | def app_label(self): 23 | raise NotImplementedError('app_label attribute must be set') 24 | 25 | def dispatch(self, request, *args, **kwargs): 26 | self.request = request 27 | 28 | if request.user.is_authenticated(): 29 | 30 | remote_user_data = {} 31 | 32 | remote_user_data['email'] = request.user.email 33 | remote_user_data['name'] = request.user.get_full_name() 34 | 35 | request.META['HTTP_REMOTE_USER_DATA'] = json.dumps( 36 | remote_user_data, 37 | sort_keys=True, 38 | ) 39 | 40 | return super(ColabProxyView, self).dispatch(request, *args, **kwargs) 41 | -------------------------------------------------------------------------------- /colab/queue/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/queue/__init__.py -------------------------------------------------------------------------------- /colab/rss/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/rss/__init__.py -------------------------------------------------------------------------------- /colab/rss/feeds.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | from django.contrib.syndication.views import Feed 5 | from django.utils.translation import ugettext as _ 6 | 7 | from haystack.query import SearchQuerySet 8 | 9 | 10 | class LatestThreadsFeeds(Feed): 11 | title = _(u'Latest Discussions') 12 | link = '/rss/threads/latest/' 13 | 14 | def items(self): 15 | return [] 16 | 17 | def item_link(self, item): 18 | return item.latest_message.url 19 | 20 | def item_title(self, item): 21 | title = '[' + item.mailinglist.name + '] ' 22 | title += item.latest_message.subject_clean 23 | return title 24 | 25 | def item_description(self, item): 26 | return item.latest_message.body 27 | 28 | 29 | class HottestThreadsFeeds(Feed): 30 | title = _(u'Discussions Most Relevance') 31 | link = '/rss/threads/hottest/' 32 | 33 | def items(self): 34 | return [] 35 | 36 | def item_link(self, item): 37 | return item.latest_message.url 38 | 39 | def item_title(self, item): 40 | title = '[' + item.mailinglist.name + '] ' 41 | title += item.latest_message.subject_clean 42 | return title 43 | 44 | def item_description(self, item): 45 | return item.latest_message.body 46 | 47 | 48 | class LatestColabFeeds(Feed): 49 | title = _(u'Latest collaborations') 50 | link = '/rss/colab/latest/' 51 | 52 | def items(self): 53 | items = SearchQuerySet().order_by('-modified', '-created')[:20] 54 | return items 55 | 56 | def item_title(self, item): 57 | type_ = item.type + ': ' 58 | mailinglist = item.tag 59 | 60 | if mailinglist: 61 | prefix = type_ + mailinglist + ' - ' 62 | else: 63 | prefix = type_ 64 | 65 | return prefix + item.title 66 | 67 | def item_description(self, item): 68 | return item.latest_description 69 | 70 | def item_link(self, item): 71 | return item.url 72 | -------------------------------------------------------------------------------- /colab/rss/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | import feeds 3 | 4 | urlpatterns = patterns('', 5 | url(r'threads/latest/$', feeds.LatestThreadsFeeds(), name='rss_latest_threads'), 6 | url(r'colab/latest/$', feeds.LatestColabFeeds(), name='rss_latest_colab'), 7 | url(r'threads/hottest/$', feeds.HottestThreadsFeeds(), name='rss_hottest_threads'), 8 | ) 9 | 10 | -------------------------------------------------------------------------------- /colab/search/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/search/__init__.py -------------------------------------------------------------------------------- /colab/search/admin.py: -------------------------------------------------------------------------------- 1 | # uncomment the import if you really use. 2 | # from django.contrib import admin 3 | 4 | # Register your models here. 5 | -------------------------------------------------------------------------------- /colab/search/fixtures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/search/fixtures/__init__.py -------------------------------------------------------------------------------- /colab/search/fixtures/test_data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "fields": { 4 | "last_name": "Administrator", 5 | "webpage": "", 6 | "twitter": "", 7 | "is_staff": true, 8 | "user_permissions": [], 9 | "date_joined": "2015-01-28T12:34:58.770Z", 10 | "google_talk": "", 11 | "first_name": "Admin", 12 | "is_superuser": true, 13 | "last_login": "2015-01-28T12:35:39.621Z", 14 | "verification_hash": null, 15 | "role": "", 16 | "email": "admin@mail.com", 17 | "username": "admin", 18 | "bio": "", 19 | "needs_update": true, 20 | "is_active": true, 21 | "facebook": "", 22 | "groups": [], 23 | "password": "pbkdf2_sha256$12000$iiKCMnLZnFJw$UTx89LB8oYTiw9UqkcglzFLmIaZtbr+ZzF1cG3vfcyo=", 24 | "institution": "", 25 | "github": "", 26 | "modified": "2015-01-28T12:45:27.375Z" 27 | }, 28 | "model": "accounts.user", 29 | "pk": 1 30 | }, 31 | { 32 | "fields": { 33 | "last_name": "Norris", 34 | "webpage": "", 35 | "twitter": "", 36 | "is_staff": true, 37 | "user_permissions": [], 38 | "date_joined": "2015-01-28T12:34:58.770Z", 39 | "google_talk": "", 40 | "first_name": "Chuck", 41 | "is_superuser": true, 42 | "last_login": "2015-01-28T12:35:39.621Z", 43 | "verification_hash": null, 44 | "role": "", 45 | "email": "chucknorris@mail.com", 46 | "username": "chucknorris", 47 | "bio": "", 48 | "needs_update": true, 49 | "is_active": true, 50 | "facebook": "", 51 | "groups": [], 52 | "password": "pbkdf2_sha256$12000$iiKCMnLZnFJw$UTx89LB8oYTiw9UqkcglzFLmIaZtbr+ZzF1cG3vfcyo=", 53 | "institution": "", 54 | "github": "", 55 | "modified": "2015-01-28T12:45:27.375Z" 56 | }, 57 | "model": "accounts.user", 58 | "pk": 2 59 | }, 60 | 61 | { 62 | "fields": { 63 | "last_name": "Norris", 64 | "webpage": "", 65 | "twitter": "", 66 | "is_staff": true, 67 | "user_permissions": [], 68 | "date_joined": "2015-01-28T12:34:58.770Z", 69 | "google_talk": "", 70 | "first_name": "Heisenberg", 71 | "is_superuser": true, 72 | "last_login": "2015-01-28T12:35:39.621Z", 73 | "verification_hash": null, 74 | "role": "", 75 | "email": "heisenberg@mail.com", 76 | "username": "heisenbergnorris", 77 | "bio": "", 78 | "needs_update": true, 79 | "is_active": true, 80 | "facebook": "", 81 | "groups": [], 82 | "password": "pbkdf2_sha256$12000$iiKCMnLZnFJw$UTx89LB8oYTiw9UqkcglzFLmIaZtbr+ZzF1cG3vfcyo=", 83 | "institution": "", 84 | "github": "", 85 | "modified": "2015-01-28T12:45:27.375Z" 86 | }, 87 | "model": "accounts.user", 88 | "pk": 3 89 | } 90 | ] 91 | -------------------------------------------------------------------------------- /colab/search/models.py: -------------------------------------------------------------------------------- 1 | # uncomment the import if you really use. 2 | # from django.db import models 3 | 4 | # Create your models here. 5 | -------------------------------------------------------------------------------- /colab/search/templates/message-preview.html: -------------------------------------------------------------------------------- 1 | {% load i18n tz highlight search_preview_templates %} 2 | {% get_dashboard_search_preview_templates result as template_target %} 3 | {% include template_target %} 4 | -------------------------------------------------------------------------------- /colab/search/templates/search-base.html: -------------------------------------------------------------------------------- 1 | {% load i18n tz highlight %} 2 | {% block content %} 3 |
    4 |
    5 | {{ modified|date:"d F Y"|default_if_none:"" }} 6 | {% if modified_time %} 7 | {% trans "at" %} {{result.modified|date:"h:m" }} 8 | {% endif %} 9 | {{author|safe|default_if_none:""}} 10 |
    11 |

    12 | {% if title %} 13 | {% highlight title with query %} 14 | {% endif %} 15 |

    16 |

    17 | {% if description != "None" %} 18 | {% highlight description with query %} 19 | {% endif %} 20 |

    21 | {% if registered_in %} 22 | {% trans "Registred in" %}: 23 | {% trans registered_in %} 24 | 25 | {% endif %} 26 |
    27 |
    28 |
    29 | {% endblock content %} -------------------------------------------------------------------------------- /colab/search/templates/search/search-user-preview.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | {{ result.name }} 7 | 8 | 9 | {% if result.institution %}- {{ result.institution }}{% endif %}{% if result.role %} - {{ result.role }}{% endif %} 10 | -------------------------------------------------------------------------------- /colab/search/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/search/templatetags/__init__.py -------------------------------------------------------------------------------- /colab/search/templatetags/get_operations.py: -------------------------------------------------------------------------------- 1 | 2 | from django import template 3 | import urllib 4 | import urlparse 5 | 6 | 7 | register = template.Library() 8 | 9 | 10 | def append_to_get_parameter(path, query=None, **kwargs): 11 | query_dict = dict(urlparse.parse_qsl(query)) 12 | for key, value in kwargs.items(): 13 | query_dict[key] = value 14 | return u'{}?{}'.format(path, urllib.urlencode(query_dict)) 15 | 16 | 17 | def pop_from_get_parameter(path, query=None, **kwargs): 18 | query_dict = dict(urlparse.parse_qsl(query)) 19 | for key, value in kwargs.items(): 20 | if query_dict not in (key): 21 | continue 22 | if query_dict[key] == value: 23 | del query_dict[key] 24 | continue 25 | if value in query_dict[key]: 26 | aux = query_dict[key].split(value) 27 | query_dict[key] = u''.join(aux).strip() 28 | return u'{}?{}'.format(path, urllib.urlencode(query_dict)) 29 | 30 | 31 | @register.simple_tag(takes_context=True) 32 | def append_to_get(context, **kwargs): 33 | return append_to_get_parameter( 34 | context['request'].META['PATH_INFO'], 35 | context['request'].META['QUERY_STRING'], 36 | **kwargs 37 | ) 38 | 39 | 40 | @register.simple_tag(takes_context=True) 41 | def pop_from_get(context, **kwargs): 42 | return pop_from_get_parameter( 43 | context['request'].META['PATH_INFO'], 44 | context['request'].META['QUERY_STRING'], 45 | **kwargs 46 | ) 47 | -------------------------------------------------------------------------------- /colab/search/templatetags/search_get.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from colab.search.utils import url 3 | 4 | 5 | register = template.Library() 6 | 7 | 8 | @register.simple_tag(takes_context=True) 9 | def append_to_get(context, **kwargs): 10 | return url.append_to_get( 11 | context['request'].META['PATH_INFO'], 12 | context['request'].META['QUERY_STRING'], 13 | **kwargs 14 | ) 15 | 16 | 17 | @register.simple_tag(takes_context=True) 18 | def pop_from_get(context, **kwargs): 19 | return url.pop_from_get( 20 | context['request'].META['PATH_INFO'], 21 | context['request'].META['QUERY_STRING'], 22 | **kwargs 23 | ) 24 | -------------------------------------------------------------------------------- /colab/search/templatetags/search_preview_templates.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | 4 | register = template.Library() 5 | 6 | 7 | @register.assignment_tag 8 | def get_search_preview_templates(model_indexed): 9 | app_type = model_indexed.type 10 | 11 | return "search/{}_search_preview.html".format(app_type) 12 | 13 | 14 | @register.assignment_tag 15 | def get_dashboard_search_preview_templates(model_indexed): 16 | app_type = model_indexed.type 17 | 18 | return "dashboard/{}_search_preview.html".format(app_type) 19 | -------------------------------------------------------------------------------- /colab/search/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/search/tests/__init__.py -------------------------------------------------------------------------------- /colab/search/tests/test_templatetags.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from django.test import TestCase 4 | from colab.search.templatetags.search_preview_templates import ( 5 | get_search_preview_templates) 6 | from mock import MagicMock, PropertyMock 7 | 8 | 9 | class SearchTemplateTagsTest(TestCase): 10 | 11 | def setUp(self): 12 | self.model_indexed_mock = MagicMock() 13 | self.template_path = "{}/{}_search_preview.html" 14 | 15 | def set_mock_value(self, value): 16 | type(self.model_indexed_mock).type = PropertyMock(return_value=value) 17 | 18 | def test_get_search_preview_templates_with_user(self): 19 | self.set_mock_value("user") 20 | include_path = get_search_preview_templates(self.model_indexed_mock) 21 | self.assertEqual(include_path, self.template_path.format("search", 22 | "user")) 23 | 24 | def test_get_search_preview_templates_with_thread(self): 25 | self.set_mock_value("thread") 26 | include_path = get_search_preview_templates(self.model_indexed_mock) 27 | self.assertEqual(include_path, 28 | self.template_path.format("search", "thread")) 29 | 30 | def test_get_search_preview_templates_with_plugin(self): 31 | self.set_mock_value("plugin_model") 32 | include_path = get_search_preview_templates(self.model_indexed_mock) 33 | self.assertEqual(include_path, 34 | self.template_path.format("search", "plugin_model")) 35 | -------------------------------------------------------------------------------- /colab/search/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from haystack.query import SearchQuerySet 3 | 4 | from .forms import ColabSearchForm 5 | from .views import ColabSearchView 6 | 7 | 8 | urlpatterns = patterns('', 9 | url(r'^$', ColabSearchView( 10 | template='search/search.html', 11 | searchqueryset=SearchQuerySet(), 12 | form_class=ColabSearchForm, 13 | ), name='haystack_search'), 14 | ) 15 | -------------------------------------------------------------------------------- /colab/search/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/search/utils/__init__.py -------------------------------------------------------------------------------- /colab/search/utils/url.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import urllib 4 | import urlparse 5 | 6 | 7 | def append_to_get(path, query=None, **kwargs): 8 | query_dict = dict(urlparse.parse_qsl(query)) 9 | for key, value in kwargs.items(): 10 | query_dict[key] = value 11 | return u'{}?{}'.format(path, urllib.urlencode(query_dict)) 12 | 13 | 14 | def pop_from_get(path, query=None, **kwargs): 15 | query_dict = dict(urlparse.parse_qsl(query)) 16 | for key, value in kwargs.items(): 17 | if query_dict not in (key): 18 | continue 19 | if query_dict[key] == value: 20 | del query_dict[key] 21 | continue 22 | if value in query_dict[key]: 23 | aux = query_dict[key].split(value) 24 | query_dict[key] = u''.join(aux).strip() 25 | return u'{}?{}'.format(path, urllib.urlencode(query_dict)) 26 | -------------------------------------------------------------------------------- /colab/search/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from django.conf import settings 4 | 5 | from haystack.views import SearchView 6 | from colab.plugins.utils import filters_importer 7 | 8 | 9 | class ColabSearchView(SearchView): 10 | def extra_context(self, *args, **kwargs): 11 | 12 | use_language, date_format = settings.DJANGO_DATE_FORMAT_TO_JS.get( 13 | self.request.LANGUAGE_CODE, (None, None) 14 | ) 15 | 16 | try: 17 | type_chosen = self.form.cleaned_data.get('type') 18 | except AttributeError: 19 | type_chosen = '' 20 | 21 | mimetype_choices = () 22 | size_choices = () 23 | used_by_choices = () 24 | 25 | mimetype_chosen = self.request.GET.get('mimetype') 26 | size_chosen = self.request.GET.get('size') 27 | used_by_chosen = self.request.GET.get('used_by') 28 | 29 | types = filters_importer.import_plugin_filters(self.request.GET) 30 | 31 | filters_options = [(k, v['name'], v['icon']) 32 | for (k, v) in types.iteritems()] 33 | return dict( 34 | filters=types.get(type_chosen), 35 | filters_options=filters_options, 36 | type_chosen=type_chosen, 37 | order_data=settings.ORDERING_DATA, 38 | date_format=date_format, 39 | use_language=use_language, 40 | mimetype_chosen=mimetype_chosen if mimetype_chosen else '', 41 | mimetype_choices=mimetype_choices, 42 | size_chosen=size_chosen if size_chosen else '', 43 | size_choices=size_choices, 44 | used_by_chosen=used_by_chosen if used_by_chosen else '', 45 | used_by_choices=used_by_choices, 46 | ) 47 | -------------------------------------------------------------------------------- /colab/signals/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/signals/__init__.py -------------------------------------------------------------------------------- /colab/signals/exceptions.py: -------------------------------------------------------------------------------- 1 | 2 | from ..exceptions import ColabException 3 | 4 | 5 | class SignalDoesNotExist(ColabException): 6 | """Expcetion raised when signal does not exist""" 7 | -------------------------------------------------------------------------------- /colab/signals/signals.py: -------------------------------------------------------------------------------- 1 | 2 | from django.dispatch import Signal 3 | 4 | from .exceptions import SignalDoesNotExist 5 | 6 | registered_signals = {} 7 | signal_instances = {} 8 | 9 | 10 | class ColabSignal(Signal): 11 | def __reduce__(self): 12 | """ 13 | 14 | In order to send a signal to a celery task, it is necessary to pickle 15 | the objects that will be used as parameters. However, 16 | django.dispatch.Signal has an instance of threading.Lock, which is an 17 | object that cannot be pickled. Therefore, this function changes the 18 | pickle behaviour of Signal, making that only the providind_args of 19 | Signal to be pickled.""" 20 | 21 | return (ColabSignal, (self.providing_args,)) 22 | 23 | 24 | def register_signal(plugin_name, list_signals): 25 | for signal in list_signals: 26 | if signal in registered_signals: 27 | if plugin_name not in registered_signals[signal]: 28 | registered_signals[signal].append(plugin_name) 29 | else: 30 | registered_signals[signal] = [] 31 | registered_signals[signal].append(plugin_name) 32 | signal_instances[signal] = ColabSignal() 33 | 34 | 35 | def connect_signal(signal_name, sender, handling_method): 36 | if signal_name in signal_instances: 37 | signal_instances[signal_name].connect(handling_method.delay, 38 | sender=sender) 39 | else: 40 | raise SignalDoesNotExist 41 | 42 | 43 | def send(signal_name, sender, **kwargs): 44 | if signal_name in signal_instances: 45 | signal_instances[signal_name].send(sender=sender, **kwargs) 46 | else: 47 | raise SignalDoesNotExist 48 | -------------------------------------------------------------------------------- /colab/signals/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/signals/tests/__init__.py -------------------------------------------------------------------------------- /colab/signals/tests/test_signals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test Signals class. 3 | Objective: Test parameters, and behavior. 4 | """ 5 | 6 | from django.test import TestCase 7 | 8 | from mock import patch, MagicMock, PropertyMock 9 | 10 | from ..signals import registered_signals, register_signal, connect_signal, send 11 | from ..exceptions import SignalDoesNotExist 12 | 13 | 14 | class SignalsTest(TestCase): 15 | 16 | def setUp(self): 17 | self.list_signal = ['a', 'b', 'c'] 18 | self.plugin_name = 'test_signal' 19 | 20 | def test_register_signal_(self): 21 | register_signal(self.plugin_name, self.list_signal) 22 | signal_name = 'a' 23 | signal_list = ['test_signal'] 24 | self.assertEqual(len(registered_signals[signal_name]), 1) 25 | self.assertEqual(registered_signals[signal_name], signal_list) 26 | 27 | def test_register_signal_already_registered(self): 28 | signal_name = 'a' 29 | signal_list = ['test_signal'] 30 | 31 | register_signal(self.plugin_name, self.list_signal) 32 | self.assertEqual(len(registered_signals[signal_name]), 1) 33 | 34 | register_signal(self.plugin_name, self.list_signal) 35 | self.assertEqual(len(registered_signals[signal_name]), 1) 36 | self.assertEqual(registered_signals[signal_name], signal_list) 37 | 38 | def test_connect_non_registered_signal(self): 39 | sender = 'Test' 40 | handling_method = 'Test' 41 | signal_name = 'Test' 42 | 43 | self.assertRaises(SignalDoesNotExist, connect_signal, signal_name, 44 | sender, handling_method) 45 | 46 | @patch('colab.signals.signals.Signal.connect') 47 | def test_connect_already_registered_signal(self, mock): 48 | sender = 'Test' 49 | handling_method = MagicMock() 50 | type(handling_method).delay = PropertyMock(return_value='Test') 51 | signal_name = 'a' 52 | 53 | register_signal(self.plugin_name, self.list_signal) 54 | 55 | connect_signal(signal_name, sender, handling_method) 56 | args, kwargs = mock.call_args 57 | 58 | self.assertEqual(args[0], handling_method.delay) 59 | self.assertEqual(kwargs['sender'], sender) 60 | self.assertTrue(mock.is_called) 61 | 62 | @patch('colab.signals.signals.Signal.send') 63 | def test_send_signal(self, mock): 64 | sender = 'Test' 65 | signal_name = 'a' 66 | 67 | register_signal(self.plugin_name, self.list_signal) 68 | send(signal_name, sender) 69 | 70 | args, kwargs = mock.call_args 71 | 72 | self.assertEqual(kwargs['sender'], sender) 73 | self.assertTrue(mock.is_called) 74 | 75 | def test_send_signal_not_registered(self): 76 | self.assertRaises(SignalDoesNotExist, send, 'test_signal', 'test') 77 | -------------------------------------------------------------------------------- /colab/static/css/footer.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/css/footer.css -------------------------------------------------------------------------------- /colab/static/css/header.css: -------------------------------------------------------------------------------- 1 | /* Header */ 2 | 3 | #header-searchbox { 4 | width: 190px; 5 | } 6 | 7 | #header-hr { 8 | margin-top: 0; 9 | } 10 | 11 | .navbar-default .navbar-brand, 12 | .navbar a.dropdown-toggle.user { 13 | padding: 0; 14 | margin-top: 5px; 15 | margin-left: 10px; 16 | } 17 | 18 | .navbar-brand img { 19 | height: 40px; 20 | } 21 | 22 | #user-menu .wrapper { 23 | padding: 3px 10px; 24 | white-space: nowrap; 25 | } 26 | 27 | #user-menu .wrapper a { 28 | margin: 5px 0; 29 | } 30 | 31 | #user-menu .user-info { 32 | display: inline-block; 33 | vertical-align: top; 34 | padding-left: 5px; 35 | } 36 | 37 | #user-menu .user-info span { 38 | display: block; 39 | } 40 | 41 | #user-menu .dropdown-menu .thumbnail { 42 | width: 100px; 43 | display: inline-block; 44 | } 45 | 46 | /* End of Header */ -------------------------------------------------------------------------------- /colab/static/img/COPYRIGHT: -------------------------------------------------------------------------------- 1 | The icons listed bellow were copied from the Iconic icons package. The icons in this set were originally designed for the Franklin Street WordPress theme and are available under CC Attribution-Share Alike 3.0 license - http://creativecommons.org/licenses/by-sa/3.0/us/ 2 | 3 | * ticket.png 4 | * changeset.png 5 | * thread.png 6 | * wiki.png 7 | * x.png 8 | * plus.png 9 | * rss.png 10 | 11 | The full Iconic package can be found here: https://github.com/downloads/somerandomdude/Iconic/iconic.zip 12 | -------------------------------------------------------------------------------- /colab/static/img/cc_by_sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/img/cc_by_sa.png -------------------------------------------------------------------------------- /colab/static/img/fav.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/img/fav.ico -------------------------------------------------------------------------------- /colab/static/img/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/img/plus.png -------------------------------------------------------------------------------- /colab/static/img/rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/img/rss.png -------------------------------------------------------------------------------- /colab/static/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/img/user.png -------------------------------------------------------------------------------- /colab/static/img/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/img/x.png -------------------------------------------------------------------------------- /colab/static/third-party/bootstrap-datetimepicker/README: -------------------------------------------------------------------------------- 1 | This bootstrap extension was copied from 2 | 3 | https://github.com/Eonasdan/bootstrap-datetimepicker 4 | ed42869337753e50adeb4a0e2476bfffc8edf2a9 5 | 6 | Distributed under Apache License Version 2.0: 7 | https://github.com/Eonasdan/bootstrap-datetimepicker/blob/master/LICENSE 8 | -------------------------------------------------------------------------------- /colab/static/third-party/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.es.js: -------------------------------------------------------------------------------- 1 | // moment.js language configuration 2 | // language : spanish (es) 3 | // author : Julio Napurí : https://github.com/julionc 4 | 5 | (function (factory) { 6 | if (typeof define === 'function' && define.amd) { 7 | define(['moment'], factory); // AMD 8 | } else if (typeof exports === 'object') { 9 | module.exports = factory(require('../moment')); // Node 10 | } else { 11 | factory(window.moment); // Browser global 12 | } 13 | }(function (moment) { 14 | return moment.lang('es', { 15 | months : "enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"), 16 | monthsShort : "ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"), 17 | weekdays : "domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"), 18 | weekdaysShort : "dom._lun._mar._mié._jue._vie._sáb.".split("_"), 19 | weekdaysMin : "Do_Lu_Ma_Mi_Ju_Vi_Sá".split("_"), 20 | longDateFormat : { 21 | LT : "H:mm", 22 | L : "DD/MM/YYYY", 23 | LL : "D [de] MMMM [de] YYYY", 24 | LLL : "D [de] MMMM [de] YYYY LT", 25 | LLLL : "dddd, D [de] MMMM [de] YYYY LT" 26 | }, 27 | calendar : { 28 | sameDay : function () { 29 | return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; 30 | }, 31 | nextDay : function () { 32 | return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; 33 | }, 34 | nextWeek : function () { 35 | return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; 36 | }, 37 | lastDay : function () { 38 | return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; 39 | }, 40 | lastWeek : function () { 41 | return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; 42 | }, 43 | sameElse : 'L' 44 | }, 45 | relativeTime : { 46 | future : "en %s", 47 | past : "hace %s", 48 | s : "unos segundos", 49 | m : "un minuto", 50 | mm : "%d minutos", 51 | h : "una hora", 52 | hh : "%d horas", 53 | d : "un día", 54 | dd : "%d días", 55 | M : "un mes", 56 | MM : "%d meses", 57 | y : "un año", 58 | yy : "%d años" 59 | }, 60 | ordinal : '%dº', 61 | week : { 62 | dow : 1, // Monday is the first day of the week. 63 | doy : 4 // The week that contains Jan 4th is the first week of the year. 64 | } 65 | }); 66 | })); 67 | -------------------------------------------------------------------------------- /colab/static/third-party/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.pt-BR.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Brazilian translation for bootstrap-datetimepicker 3 | * Cauan Cabral 4 | */ 5 | ;(function($){ 6 | $.fn.datetimepicker.dates['pt-BR'] = { 7 | days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], 8 | daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], 9 | daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], 10 | months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], 11 | monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 12 | today: "Hoje" 13 | }; 14 | }(jQuery)); 15 | -------------------------------------------------------------------------------- /colab/static/third-party/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /colab/static/third-party/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /colab/static/third-party/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /colab/static/third-party/font-awesome/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/font-awesome/font/FontAwesome.otf -------------------------------------------------------------------------------- /colab/static/third-party/font-awesome/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/font-awesome/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /colab/static/third-party/font-awesome/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/font-awesome/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /colab/static/third-party/font-awesome/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/static/third-party/font-awesome/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /colab/static/third-party/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.3.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2013 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function ($, document, undefined) { 9 | 10 | var pluses = /\+/g; 11 | 12 | function raw(s) { 13 | return s; 14 | } 15 | 16 | function decoded(s) { 17 | return unRfc2068(decodeURIComponent(s.replace(pluses, ' '))); 18 | } 19 | 20 | function unRfc2068(value) { 21 | if (value.indexOf('"') === 0) { 22 | // This is a quoted cookie as according to RFC2068, unescape 23 | value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 24 | } 25 | return value; 26 | } 27 | 28 | function fromJSON(value) { 29 | return config.json ? JSON.parse(value) : value; 30 | } 31 | 32 | var config = $.cookie = function (key, value, options) { 33 | 34 | // write 35 | if (value !== undefined) { 36 | options = $.extend({}, config.defaults, options); 37 | 38 | if (value === null) { 39 | options.expires = -1; 40 | } 41 | 42 | if (typeof options.expires === 'number') { 43 | var days = options.expires, t = options.expires = new Date(); 44 | t.setDate(t.getDate() + days); 45 | } 46 | 47 | value = config.json ? JSON.stringify(value) : String(value); 48 | 49 | return (document.cookie = [ 50 | encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), 51 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 52 | options.path ? '; path=' + options.path : '', 53 | options.domain ? '; domain=' + options.domain : '', 54 | options.secure ? '; secure' : '' 55 | ].join('')); 56 | } 57 | 58 | // read 59 | var decode = config.raw ? raw : decoded; 60 | var cookies = document.cookie.split('; '); 61 | var result = key ? null : {}; 62 | for (var i = 0, l = cookies.length; i < l; i++) { 63 | var parts = cookies[i].split('='); 64 | var name = decode(parts.shift()); 65 | var cookie = decode(parts.join('=')); 66 | 67 | if (key && key === name) { 68 | result = fromJSON(cookie); 69 | break; 70 | } 71 | 72 | if (!key) { 73 | result[name] = fromJSON(cookie); 74 | } 75 | } 76 | 77 | return result; 78 | }; 79 | 80 | config.defaults = {}; 81 | 82 | $.removeCookie = function (key, options) { 83 | if ($.cookie(key) !== null) { 84 | $.cookie(key, null, options); 85 | return true; 86 | } 87 | return false; 88 | }; 89 | 90 | })(jQuery, document); 91 | -------------------------------------------------------------------------------- /colab/static/third-party/jquery.debouncedresize.js: -------------------------------------------------------------------------------- 1 | /* 2 | * debouncedresize: special jQuery event that happens once after a window resize 3 | * 4 | * latest version and complete README available on Github: 5 | * https://github.com/louisremi/jquery-smartresize 6 | * 7 | * Copyright 2012 @louis_remi 8 | * Licensed under the MIT license. 9 | * 10 | * This saved you an hour of work? 11 | * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON 12 | */ 13 | (function($) { 14 | 15 | var $event = $.event, 16 | $special, 17 | resizeTimeout; 18 | 19 | $special = $event.special.debouncedresize = { 20 | setup: function() { 21 | $( this ).on( "resize", $special.handler ); 22 | }, 23 | teardown: function() { 24 | $( this ).off( "resize", $special.handler ); 25 | }, 26 | handler: function( event, execAsap ) { 27 | // Save the context 28 | var context = this, 29 | args = arguments, 30 | dispatch = function() { 31 | // set correct event type 32 | event.type = "debouncedresize"; 33 | $event.dispatch.apply( context, args ); 34 | }; 35 | 36 | if ( resizeTimeout ) { 37 | clearTimeout( resizeTimeout ); 38 | } 39 | 40 | execAsap ? 41 | dispatch() : 42 | resizeTimeout = setTimeout( dispatch, $special.threshold ); 43 | }, 44 | threshold: 150 45 | }; 46 | 47 | })(jQuery); -------------------------------------------------------------------------------- /colab/super_archives/tests/test_utils_collaborations.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from django.test import TestCase 4 | from colab.super_archives.utils.collaborations import count_threads 5 | 6 | 7 | class CollaborationTest(TestCase): 8 | 9 | fixtures = ['mailinglistdata.json'] 10 | 11 | def test_count_threads(self): 12 | self.assertEquals(count_threads(), 5) 13 | -------------------------------------------------------------------------------- /colab/templates/403.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block main-content %} 5 |

    {% trans "You can't be here :/" %}

    6 | {% endblock %} 7 | 8 | {% block footer %}{% endblock %} 9 | -------------------------------------------------------------------------------- /colab/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block main-content %} 5 |

    {% trans "Not found. Keep searching! :)" %}

    6 | {% endblock %} 7 | 8 | {% block footer %}{% endblock %} 9 | -------------------------------------------------------------------------------- /colab/templates/500.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

    {% trans "Ooopz... something went wrong!" %}

    3 |

    Internal Server Error

    4 | -------------------------------------------------------------------------------- /colab/templates/doughnut-chart.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load static from staticfiles %} 3 | 4 | 5 | 6 | 7 | 46 | -------------------------------------------------------------------------------- /colab/templates/footer.html: -------------------------------------------------------------------------------- 1 | {% load i18n gravatar plugins %} 2 | {% load static from staticfiles %} 3 | 4 | 18 | -------------------------------------------------------------------------------- /colab/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n widgets_tag%} 3 | 4 | {% block html %} 5 | {% import_widgets 'dashboard' %} 6 | {{block.super}} 7 | {% endblock %} 8 | 9 | {% block pagetitle %}Home{% endblock %} 10 | 11 | {% block head_js %} 12 | {% for widget in widgets_dashboard %} 13 | {{widget.get_header}} 14 | {% endfor %} 15 | {% endblock %} 16 | 17 | {% block main-content %} 18 |
    19 | {% for widget in widgets_dashboard %} 20 |
    21 |
    22 | {{widget.get_body}} 23 |
    24 |
    25 | {% endfor %} 26 |
    27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /colab/templates/includes/google_analytics.html: -------------------------------------------------------------------------------- 1 | 2 | {% if GOOGLE_ANALYTICS_TRACKING_ID %} 3 | 4 | 15 | {% endif %} 16 | -------------------------------------------------------------------------------- /colab/templates/pizza-chart.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load static from staticfiles %} 3 | 4 | 5 | 45 | -------------------------------------------------------------------------------- /colab/tz/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/tz/__init__.py -------------------------------------------------------------------------------- /colab/tz/middleware.py: -------------------------------------------------------------------------------- 1 | 2 | import pytz 3 | 4 | from django.utils import timezone 5 | 6 | 7 | class TimezoneMiddleware(object): 8 | def process_request(self, request): 9 | offset = request.COOKIES.get('utc_offset', 0) 10 | 11 | try: 12 | offset = int(offset) * -1 13 | tz = pytz.FixedOffset(offset) 14 | except ValueError: 15 | offset = 0 16 | 17 | if offset: 18 | timezone.activate(tz) 19 | else: 20 | timezone.deactivate() 21 | -------------------------------------------------------------------------------- /colab/tz/templates/tz/set_utc_offset.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /colab/tz/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/tz/tests/__init__.py -------------------------------------------------------------------------------- /colab/tz/tests/test_middleware.py: -------------------------------------------------------------------------------- 1 | from mock import Mock, patch 2 | 3 | from django.test import TestCase 4 | from colab.tz.middleware import TimezoneMiddleware 5 | 6 | 7 | class TimezoneMiddlewareTest(TestCase): 8 | 9 | @patch('colab.tz.middleware.timezone.activate') 10 | def test_process_request_with_utc_offset(self, mock_timezone): 11 | mock_timezone.return_value = {} 12 | request = Mock(COOKIES={'utc_offset': 120}) 13 | timezonemiddleware = TimezoneMiddleware() 14 | timezonemiddleware.process_request(request) 15 | self.assertTrue(mock_timezone.called) 16 | 17 | @patch('colab.tz.middleware.timezone.deactivate') 18 | def test_process_request_without_utc_offset(self, mock_timezone): 19 | mock_timezone.return_value = {} 20 | request = Mock(COOKIES={}) 21 | timezonemiddleware = TimezoneMiddleware() 22 | timezonemiddleware.process_request(request) 23 | self.assertTrue(mock_timezone.called) 24 | 25 | @patch('colab.tz.middleware.pytz.FixedOffset') 26 | @patch('colab.tz.middleware.timezone.deactivate') 27 | def test_process_request_value_error(self, mock_timezone, mock_pytz): 28 | mock_pytz.side_effect = ValueError 29 | 30 | request = Mock(COOKIES={'utc_offset': 120}) 31 | 32 | timezonemiddleware = TimezoneMiddleware() 33 | timezonemiddleware.process_request(request) 34 | self.assertTrue(mock_timezone.called) 35 | -------------------------------------------------------------------------------- /colab/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from django.conf import settings 3 | from django.contrib import admin 4 | from django.views.generic import RedirectView 5 | from django.views.defaults import permission_denied 6 | 7 | admin.autodiscover() 8 | 9 | urlpatterns = [] 10 | 11 | colab_plugins = settings.COLAB_APPS 12 | 13 | for plugin in colab_plugins: 14 | colab_plugin = colab_plugins.get(plugin) 15 | plugin_blacklist = colab_plugin.get('blacklist') 16 | if plugin_blacklist: 17 | for plugin_url in plugin_blacklist: 18 | final_url = colab_plugin.get('urls').get('prefix') 19 | final_url += plugin_url 20 | urlpatterns += patterns( 21 | '', url(final_url, permission_denied)) 22 | 23 | if hasattr(settings, 'BLACKLIST'): 24 | core_blacklist = settings.BLACKLIST 25 | for core_url in core_blacklist: 26 | urlpatterns += patterns('', url(core_url, permission_denied)) 27 | 28 | 29 | urlpatterns += patterns( 30 | '', 31 | url(r'^$', RedirectView.as_view(url=settings.COLAB_HOME_URL), name='home'), 32 | url(r'', include('colab.plugins.urls')), 33 | url(r'^robots.txt$', 'colab.home.views.robots', name='robots'), 34 | url(r'^dashboard$', 'colab.home.views.dashboard', name='dashboard'), 35 | url(r'^search/', include('colab.search.urls')), 36 | url(r'^rss/', include('colab.rss.urls')), 37 | 38 | url(r'^account/', include('colab.accounts.urls')), 39 | url(r'^myaccount/(?P.*)$', 40 | 'colab.accounts.views.myaccount_redirect', name='myaccount'), 41 | 42 | url(r'^media/(.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}), 43 | url(r'^colab/admin/', include(admin.site.urls)), 44 | 45 | ) 46 | -------------------------------------------------------------------------------- /colab/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/utils/__init__.py -------------------------------------------------------------------------------- /colab/utils/highlighting.py: -------------------------------------------------------------------------------- 1 | from haystack.utils import Highlighter 2 | from django.conf import settings 3 | from django.utils.html import escape, strip_tags 4 | 5 | 6 | class ColabHighlighter(Highlighter): 7 | def highlight(self, text_block): 8 | self.text_block = escape(strip_tags(text_block)) 9 | highlight_locations = self.find_highlightable_words() 10 | start_offset, end_offset = self.find_window(highlight_locations) 11 | return self.render_html(highlight_locations, start_offset, end_offset) 12 | 13 | def find_window(self, highlight_locations): 14 | """Getting the HIGHLIGHT_NUM_CHARS_BEFORE_MATCH setting 15 | to find how many characters before the first word found should 16 | be removed from the window 17 | """ 18 | 19 | if len(self.text_block) <= self.max_length: 20 | return (0, self.max_length) 21 | 22 | num_chars_before = getattr( 23 | settings, 24 | 'HIGHLIGHT_NUM_CHARS_BEFORE_MATCH', 25 | 0 26 | ) 27 | 28 | best_start, best_end = super(ColabHighlighter, self).find_window( 29 | highlight_locations 30 | ) 31 | if best_start <= num_chars_before: 32 | best_end -= best_start 33 | best_start = 0 34 | else: 35 | best_start -= num_chars_before 36 | best_end -= num_chars_before 37 | 38 | return (best_start, best_end) 39 | -------------------------------------------------------------------------------- /colab/utils/runner.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import sys 4 | 5 | from django.core.management import ManagementUtility 6 | from colab.management.commands import initconfig 7 | 8 | 9 | def execute_from_command_line(argv=None): 10 | """ 11 | A simple method that runs a ManagementUtility. 12 | """ 13 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "colab.settings") 14 | from django.conf import settings 15 | 16 | if not hasattr(settings, 'SECRET_KEY') and 'initconfig' in sys.argv: 17 | command = initconfig.Command() 18 | command.handle() 19 | else: 20 | utility = ManagementUtility(argv) 21 | utility.execute() 22 | -------------------------------------------------------------------------------- /colab/utils/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/utils/tests/__init__.py -------------------------------------------------------------------------------- /colab/utils/tests/colab_settings.py: -------------------------------------------------------------------------------- 1 | from colab.settings import INSTALLED_APPS 2 | 3 | # Set to false in production 4 | DEBUG = True 5 | TEMPLATE_DEBUG = False 6 | 7 | # System admins 8 | ADMINS = [['John Foo', 'john@example.com'], ['Mary Bar', 'mary@example.com']] 9 | 10 | MANAGERS = ADMINS 11 | 12 | COLAB_FROM_ADDRESS = '"Colab" ' 13 | SERVER_EMAIL = '"Colab" ' 14 | 15 | EMAIL_HOST = 'localhost' 16 | EMAIL_PORT = 25 17 | EMAIL_SUBJECT_PREFIX = '[colab]' 18 | 19 | SECRET_KEY = 'not-a-secret' 20 | 21 | ALLOWED_HOSTS = [ 22 | 'localhost', 23 | ] 24 | 25 | # Uncomment to enable social networks fields profile 26 | SOCIAL_NETWORK_ENABLED = True 27 | 28 | # Disable indexing 29 | ROBOTS_NOINDEX = True 30 | 31 | LOGGING = { 32 | 'version': 1, 33 | 34 | 'handlers': { 35 | 'null': { 36 | 'level': 'DEBUG', 37 | 'class': 'logging.NullHandler', 38 | }, 39 | }, 40 | 41 | 'loggers': { 42 | 'colab.mailman': { 43 | 'handlers': ['null'], 44 | 'propagate': False, 45 | }, 46 | 'haystack': { 47 | 'handlers': ['null'], 48 | 'propagate': False, 49 | }, 50 | }, 51 | } 52 | 53 | STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' 54 | 55 | INSTALLED_APPS += ('behave_django', ) 56 | -------------------------------------------------------------------------------- /colab/utils/tests/plugins.d/gitlab.py: -------------------------------------------------------------------------------- 1 | from colab.plugins.utils.menu import colab_url_factory 2 | 3 | name = "gitlab" 4 | verbose_name = "Gitlab" 5 | 6 | upstream = 'https://localhost/gitlab/' 7 | private_token = 'AVA8vrohDpoSws41zd1w' 8 | 9 | urls = { 10 | "include": "gitlab.urls", 11 | "prefix": 'gitlab/', 12 | "namespace": "gitlab" 13 | } 14 | 15 | url = colab_url_factory('gitlab') 16 | -------------------------------------------------------------------------------- /colab/utils/tests/plugins.d/noosfero.py: -------------------------------------------------------------------------------- 1 | from colab.plugins.utils.menu import colab_url_factory 2 | 3 | name = "noosfero" 4 | verbose_name = "Noosfero" 5 | private_token = "ef9a334177c620b68e75a89844e8a402" 6 | 7 | upstream = 'http://localhost/social/' 8 | 9 | urls = { 10 | "include": "noosfero.urls", 11 | "prefix": '^social/', 12 | "namespace": "social" 13 | } 14 | 15 | url = colab_url_factory('social') 16 | -------------------------------------------------------------------------------- /colab/utils/tests/plugins.d/plugin_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/utils/tests/plugins.d/plugin_test -------------------------------------------------------------------------------- /colab/utils/tests/plugins.d/spb.py: -------------------------------------------------------------------------------- 1 | from colab.plugins.utils.menu import colab_url_factory 2 | 3 | verbose_name = "SPB Plugin" 4 | urls = { 5 | "include": "colab_spb.urls", 6 | "prefix": '^spb/', 7 | "namespace": "colab_spb" 8 | } 9 | 10 | url = colab_url_factory('colab_spb') 11 | -------------------------------------------------------------------------------- /colab/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/widgets/__init__.py -------------------------------------------------------------------------------- /colab/widgets/admin.py: -------------------------------------------------------------------------------- 1 | # from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /colab/widgets/dashboard/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/widgets/dashboard/__init__.py -------------------------------------------------------------------------------- /colab/widgets/dashboard/dashboard_collaboration_graph.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import Widget 2 | 3 | 4 | class DashboardCollaborationGraphWidget(Widget): 5 | name = 'Collaboration Graph' 6 | template = 'widgets/dashboard_collaboration_graph.html' 7 | -------------------------------------------------------------------------------- /colab/widgets/dashboard/dashboard_latest_collaborations.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import Widget 2 | 3 | 4 | class DashboardLatestCollaborationsWidget(Widget): 5 | name = 'Latest Collaborations' 6 | template = 'widgets/dashboard_latest_collaborations.html' 7 | -------------------------------------------------------------------------------- /colab/widgets/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/widgets/migrations/__init__.py -------------------------------------------------------------------------------- /colab/widgets/models.py: -------------------------------------------------------------------------------- 1 | # from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /colab/widgets/profile_widget.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import Widget 2 | from django.conf import settings 3 | 4 | 5 | class ProfileWidget(Widget): 6 | app_name = None 7 | colab_form = None 8 | request = None 9 | _prefix = None 10 | bootstrap_conflict = False 11 | jquery_conflict = False 12 | 13 | @property 14 | def prefix(self): 15 | if self._prefix is None: 16 | urls = settings.COLAB_APPS[self.app_name].get('urls') 17 | self._prefix = urls.get('prefix').replace('^', '/') 18 | return self._prefix 19 | 20 | def default_url(self, request): 21 | raise NotImplementedError("Please Implement this method") 22 | 23 | def fix_url(self, url): 24 | cut = 0 25 | if self.prefix in url: 26 | cut = url.find(self.prefix) + len(self.prefix) 27 | return url[cut:] 28 | 29 | def is_colab_form(self, request): 30 | if self.colab_form is None: 31 | self.colab_form = request.POST.get('colab_form', False) 32 | return self.colab_form 33 | 34 | def must_respond(self, request): 35 | if self.is_colab_form(request): 36 | return False 37 | return self.prefix in request.GET.get('path', '') or \ 38 | self.prefix in request.POST.get('path', '') 39 | 40 | def change_request_method(self, request): 41 | request.method = 'GET' 42 | 43 | if self.must_respond(request) and len(request.POST) > 0: 44 | if not request.POST.get('_method', None): 45 | request.method = "POST" 46 | else: 47 | request.method = request.POST.get("_method").upper() 48 | 49 | def requested_url(self, request): 50 | url = request.POST.get('path', request.GET.get('path', '')) 51 | 52 | if not url or not self.must_respond(request): 53 | url = self.default_url(request) 54 | 55 | return self.fix_url(url) 56 | 57 | def dispatch(self, request, url): 58 | raise NotImplementedError("Please Implement this method") 59 | 60 | def generate_content(self, **kwargs): 61 | request = kwargs.get('context', {}).get('request', None) 62 | self.change_request_method(request) 63 | response = self.dispatch(request, self.requested_url(request)) 64 | 65 | if hasattr(response, 'content'): 66 | self.content = response.content 67 | else: 68 | self.content = "".join(response.streaming_content) 69 | -------------------------------------------------------------------------------- /colab/widgets/templates/widgets/dashboard_collaboration_graph.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | {% trans "Contributions" as collabs_name %} 4 | {% include "doughnut-chart.html" with chart_data=type_count chart_canvas="collabs" name=collabs_name %} 5 | 6 | 7 |

    {% trans "Collaboration Graph" %}

    8 |
    9 | 10 |

    11 |
    12 | 13 | -------------------------------------------------------------------------------- /colab/widgets/templates/widgets/dashboard_latest_collaborations.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 4 | 5 | 6 | 7 |

    8 | {% trans "Latest Collaborations" %} 9 |

    10 | 13 | 14 |
      15 | {% for result in latest_results %} 16 | {% include "message-preview.html" %} 17 | {% endfor %} 18 |
    19 | 21 | {% trans "View more collaborations..." %} 22 | 23 |
     
    24 | 25 | -------------------------------------------------------------------------------- /colab/widgets/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/widgets/templatetags/__init__.py -------------------------------------------------------------------------------- /colab/widgets/templatetags/widgets_tag.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from colab.widgets.widget_manager import WidgetManager 3 | 4 | 5 | register = template.Library() 6 | 7 | 8 | @register.simple_tag(takes_context=True) 9 | def import_widgets(context, area_id, widget_var=None): 10 | if not widget_var: 11 | widget_var = "widgets_{}".format(area_id) 12 | 13 | context[widget_var] = WidgetManager.get_widgets(area_id, context=context) 14 | context['bootstrap_conflict'] = WidgetManager.bootstrap_conflict 15 | context['jquery_conflict'] = WidgetManager.jquery_conflict 16 | 17 | return "" 18 | -------------------------------------------------------------------------------- /colab/widgets/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/colab/widgets/tests/__init__.py -------------------------------------------------------------------------------- /colab/widgets/tests/test_widgets.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from mock import patch 3 | 4 | from colab.widgets.templatetags.widgets_tag import import_widgets 5 | from colab.widgets.widget_manager import WidgetManager, Widget 6 | from django.template import Context 7 | 8 | 9 | class WidgetMock(Widget): 10 | 11 | def __init__(self, content=""): 12 | self.content = content 13 | 14 | 15 | class WidgetsTest(unittest.TestCase): 16 | 17 | @patch.object(WidgetManager, 'get_widgets') 18 | def test_import_widgets_tag(self, get_widgets): 19 | return_list = [WidgetMock(), WidgetMock(), WidgetMock()] 20 | get_widgets.return_value = return_list 21 | 22 | context = Context({'request': ""}) 23 | import_widgets(context, 'area') 24 | 25 | self.assertIn('widgets_area', context) 26 | self.assertEquals(context['widgets_area'], return_list) 27 | 28 | @patch.object(WidgetManager, 'get_widgets') 29 | def test_import_widgets_tag_with_named_var(self, get_widgets): 30 | return_list = [WidgetMock(), WidgetMock(), WidgetMock()] 31 | get_widgets.return_value = return_list 32 | 33 | context = Context({'request': ""}) 34 | import_widgets(context, 'area', 'var') 35 | 36 | self.assertIn('var', context) 37 | self.assertEquals(context['var'], return_list) 38 | -------------------------------------------------------------------------------- /colab/widgets/views.py: -------------------------------------------------------------------------------- 1 | # from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /colab/widgets/widget_manager.py: -------------------------------------------------------------------------------- 1 | from django.utils.safestring import mark_safe 2 | from django.template.loader import render_to_string 3 | 4 | 5 | class Widget(object): 6 | identifier = None 7 | name = None 8 | content = '' 9 | template = '' 10 | bootstrap_conflict = False 11 | jquery_conflict = False 12 | 13 | def get_body(self): 14 | start = self.content.find('', start) 16 | end = self.content.find('') 17 | 18 | if -1 in [start, end]: 19 | return self.content 20 | 21 | # 1 correspond to string size of '>' 22 | body = self.content[start + 1:end] 23 | return mark_safe(body) 24 | 25 | def get_header(self): 26 | # avoiding regex in favor of performance 27 | start = self.content.find('') 28 | end = self.content.find('') 29 | 30 | if -1 in [start, end]: 31 | return '' 32 | 33 | head = self.content[start + len(''):end] 34 | return mark_safe(head) 35 | 36 | def generate_content(self, **kwargs): 37 | if not self.template: 38 | class_name = self.__class__.__name__ 39 | raise Exception("Template not defined in {}.".format(class_name)) 40 | self.content = render_to_string(self.template, kwargs.get('context')) 41 | return kwargs.get('context') 42 | 43 | 44 | class WidgetManager(object): 45 | widget_categories = {} 46 | bootstrap_conflict = False 47 | jquery_conflict = False 48 | 49 | @staticmethod 50 | def register_widget(category, widget): 51 | if category not in WidgetManager.widget_categories: 52 | WidgetManager.widget_categories[category] = [] 53 | 54 | WidgetManager.widget_categories[category].append(widget) 55 | 56 | @staticmethod 57 | def unregister_widget(category, widget_identifier): 58 | if category in WidgetManager.widget_categories: 59 | for widget in WidgetManager.widget_categories[category]: 60 | if widget.identifier == widget_identifier: 61 | WidgetManager.widget_categories[category].remove(widget) 62 | 63 | @staticmethod 64 | def get_widgets(category, **kwargs): 65 | if category not in WidgetManager.widget_categories: 66 | return [] 67 | 68 | widgets = WidgetManager.widget_categories[category][:] 69 | for widget in widgets: 70 | widget.generate_content(**kwargs) 71 | 72 | if not WidgetManager.bootstrap_conflict and \ 73 | widget.bootstrap_conflict: 74 | WidgetManager.bootstrap_conflict = True 75 | 76 | if not WidgetManager.jquery_conflict and \ 77 | widget.jquery_conflict: 78 | WidgetManager.jquery_conflict = True 79 | 80 | return widgets 81 | -------------------------------------------------------------------------------- /colab/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for colab 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/dev/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", "colab.settings") 15 | application = get_wsgi_application() 16 | -------------------------------------------------------------------------------- /diagrama_classes.asta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/diagrama_classes.asta -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. colab documentation master file, created by 2 | sphinx-quickstart on Thu Jan 22 10:59:39 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Colab - Integration Server for Web Applications 7 | =============================================== 8 | 9 | Colab is an integration server meant to help develpers to unify the **User Experience** in Web applications. 10 | 11 | Colab provides ways to integrate: 12 | 13 | * Authentication or Single Sign-On (SSO) 14 | * User Interface (UI) 15 | * Data 16 | 17 | To accomplish that Colab is placed in front of integrated Web applications. All user requests and responses are proxied (as in the image :ref:`image-reverse-proxy`) and therefore can have content and headers modified. Also, due to it's architecture, Colab can grant or deny access to systems under it. 18 | 19 | .. _image-reverse-proxy: 20 | 21 | .. figure:: static/colab-basics.jpg 22 | :width: 400 px 23 | :align: center 24 | 25 | *Colab Reverse Proxy model* 26 | 27 | Plugins are used in order to integrate new Web applications. Currently the following plugins are available and maintained by core developers: 28 | 29 | * Mailman 30 | * Gitlab 31 | * Trac 32 | * Jenkins 33 | 34 | If you need to integrate a diffirent tool please refer to :ref:`plugin-dev`. 35 | 36 | Contents: 37 | 38 | .. toctree:: 39 | :maxdepth: 2 40 | 41 | user 42 | plugindev 43 | dev 44 | 45 | 46 | Indices and tables 47 | ================== 48 | 49 | * :ref:`genindex` 50 | * :ref:`modindex` 51 | * :ref:`search` 52 | 53 | -------------------------------------------------------------------------------- /docs/source/static/colab-basics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/docs/source/static/colab-basics.jpg -------------------------------------------------------------------------------- /features/environment.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | 4 | def before_feature(context, feature): 5 | context.driver = webdriver.Firefox() 6 | context.driver.set_window_size(1000, 600) 7 | context.driver.implicitly_wait(5) 8 | 9 | 10 | def after_feature(context, feature): 11 | context.driver.quit() 12 | -------------------------------------------------------------------------------- /features/home_redirect.feature: -------------------------------------------------------------------------------- 1 | 2 | Feature: Home redirect 3 | In order to be able to choose the home page 4 | As a developer 5 | I want to be able to set a custom redirect when the user access the home page 6 | 7 | Scenario: default configuration for home page 8 | When I access the URL "/" 9 | Then The browser URL should be "/dashboard" 10 | -------------------------------------------------------------------------------- /features/steps/user_steps.py: -------------------------------------------------------------------------------- 1 | from colab.accounts.models import User 2 | from behave import given, when 3 | 4 | 5 | @given(u'The user "{username}" with the password "{password}" is "{status}"') 6 | def create_user(context, username, password, status): 7 | user = User() 8 | user.username = username 9 | user.set_password(password) 10 | user.email = "usertest@colab.com.br" 11 | user.id = 1 12 | user.first_name = "USERtestCoLaB" 13 | user.last_name = "COLAB" 14 | user.needs_update = False 15 | if status == "active": 16 | user.is_active = True 17 | else: 18 | user.is_active = False 19 | user.save() 20 | 21 | 22 | @given(u'I am logged in as "{username}"') 23 | def step_impl(context, username): 24 | context.execute_steps(''' 25 | When I access the URL "/" 26 | When I click in "Acesso " 27 | When I click in "Login" 28 | Given The user "%s" with the password "%s" is "%s" 29 | When I fill "%s" in "id_username" field 30 | When I fill "%s" in "id_password" field 31 | When I click in "Login" button 32 | ''' % (username, username, 'active', username, username)) 33 | 34 | 35 | @when(u'I open the user menu') 36 | def step_impl(context): 37 | dropdown = context.driver.find_element_by_id('user-menu') 38 | dropdown.find_element_by_xpath('.//a').click() 39 | -------------------------------------------------------------------------------- /features/steps/web_steps.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.keys import Keys 2 | from behave import when, then 3 | 4 | 5 | @when(u'I access the URL "{url}"') 6 | def step_impl(context, url): 7 | context.driver.get(context.base_url + "/") 8 | 9 | 10 | @when(u'I click in "{link}"') 11 | def step_impl(context, link): 12 | context.driver.find_element_by_xpath("//a[contains(., '%s')]" % 13 | link).click() 14 | 15 | 16 | @when(u'I click in "{button_value}" button') 17 | def step_impl(context, button_value): 18 | context.driver.find_element_by_xpath( 19 | "//input[@value='%s']|//button[.='%s']" % 20 | (button_value, button_value)).click() 21 | 22 | 23 | @when(u'I fill "{text}" in "{field_id}" field') 24 | def step_impl(context, text, field_id): 25 | field = context.driver.find_element_by_id(field_id) 26 | field.clear() 27 | field.send_keys(text) 28 | 29 | 30 | @when(u'I fill "{text}" in "{field_id}" field and hit enter') 31 | def step_impl(context, text, field_id): 32 | field = context.driver.find_element_by_id(field_id) 33 | field.clear() 34 | field.send_keys(text) 35 | field.send_keys(Keys.RETURN) 36 | 37 | 38 | @then(u'The field "{field_id}" should have an error') 39 | def step_impl(context, field_id): 40 | field = context.driver.find_element_by_id(field_id) 41 | container = field.find_element_by_xpath('..') 42 | classes = container.get_attribute('class') 43 | assert 'has-error' in classes 44 | 45 | 46 | @then(u'I should see "{content}" in "{element_id}"') 47 | def step_impl(context, content, element_id): 48 | element = context.driver.find_element_by_id(element_id) 49 | assert (content in element.text) or \ 50 | (content in element.get_attribute("value")) 51 | 52 | 53 | @then(u'The browser URL should be "{url}"') 54 | def step_impl(context, url): 55 | assert context.driver.current_url.endswith(url) 56 | -------------------------------------------------------------------------------- /features/user_sign_up.feature: -------------------------------------------------------------------------------- 1 | 2 | Feature: User Sign Up 3 | In order to use the system 4 | As an User 5 | I want to be able to sign up 6 | 7 | Scenario: Sign up with no information 8 | When I access the URL "/" 9 | When I click in "Acesso " 10 | When I click in "Register" 11 | When I click in "Register" button 12 | Then The field "id_username" should have an error 13 | Then The field "id_first_name" should have an error 14 | Then The field "id_last_name" should have an error 15 | Then The field "id_email" should have an error 16 | Then The field "id_password1" should have an error 17 | Then The field "id_password2" should have an error 18 | 19 | Scenario: Sign up with all required information 20 | When I access the URL "/" 21 | When I click in "Acesso " 22 | When I click in "Register" 23 | When I fill "johndiehard" in "id_username" field 24 | When I fill "John" in "id_first_name" field 25 | When I fill "McClane" in "id_last_name" field 26 | When I fill "john@email.com" in "id_email" field 27 | When I fill "100guns100" in "id_password1" field 28 | When I fill "100guns100" in "id_password2" field 29 | When I click in "Register" button 30 | Then The browser URL should be "/account/johndiehard" 31 | Then I should see "John McClane" in "user-profile" 32 | 33 | Scenario: Sign up with invalid email 34 | When I access the URL "/" 35 | When I click in "Acesso " 36 | When I click in "Register" 37 | When I fill "johndiehard" in "id_username" field 38 | When I fill "John" in "id_first_name" field 39 | When I fill "McClane" in "id_last_name" field 40 | When I fill "john@email" in "id_email" field 41 | When I fill "100guns100" in "id_password1" field 42 | When I fill "100guns100" in "id_password2" field 43 | When I click in "Register" button 44 | Then The field "id_email" should have an error 45 | 46 | Scenario: Sign up with different passwords 47 | When I access the URL "/" 48 | When I click in "Acesso " 49 | When I click in "Register" 50 | When I fill "johndiehard" in "id_username" field 51 | When I fill "John" in "id_first_name" field 52 | When I fill "McClane" in "id_last_name" field 53 | When I fill "john@email.com" in "id_email" field 54 | When I fill "100guns100" in "id_password1" field 55 | When I fill "100guns999" in "id_password2" field 56 | When I click in "Register" button 57 | Then The field "id_password2" should have an error 58 | -------------------------------------------------------------------------------- /misc/etc/colab/gunicorn.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | 3 | bind = "0.0.0.0:8000" 4 | workers = multiprocessing.cpu_count() * 2 + 1 5 | syslog = True 6 | proc_name = "colab" 7 | -------------------------------------------------------------------------------- /misc/etc/colab/plugins.d/audiencias.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | name = 'colab_audiencias' 4 | verbose_name = 'Colab Audiencias Plugin Plugin' 5 | 6 | upstream = 'http://audienciasweb:8000/audiencias/' 7 | api_key = config('AUDIENCIAS_API_KEY') 8 | 9 | urls = { 10 | 'include': 'colab_audiencias.urls', 11 | 'prefix': '^audiencias/', 12 | 'login': '/audiencas/accounts/login/', 13 | } 14 | -------------------------------------------------------------------------------- /misc/etc/colab/plugins.d/discourse.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | name = 'colab_discourse' 4 | verbose_name = 'Colab Discourse Plugin Plugin' 5 | 6 | upstream = 'http://discourse:8080/expressao/' 7 | api_key = config('DISCOURSE_API_KEY') 8 | api_username = config('DISCOURSE_API_USERNAME') 9 | sso_secret = config('DISCOURSE_SSO_SECRET') 10 | 11 | urls = { 12 | 'include': 'colab_discourse.urls', 13 | 'prefix': '^expressao/', 14 | 'login': '/expressao/accounts/login/', 15 | } 16 | 17 | settings_variables = { 18 | 'COLAB_STATICS': [ 19 | '/usr/lib/python2.7/site-packages/colab_discourse/static' 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /misc/etc/colab/plugins.d/edemocracia.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | name = 'colab_edemocracia' 4 | verbose_name = 'Colab eDemocracia Plugin' 5 | 6 | urls = { 7 | 'include': 'colab_edemocracia.urls', 8 | 'prefix': '', 9 | 'namespace': 'colab_edemocracia', 10 | 'login': '/home' 11 | } 12 | 13 | middlewares = ['colab_edemocracia.middlewares.ForceLangMiddleware'] 14 | 15 | dependencies = ['djangobower', 'compressor', 'easy_thumbnails', 16 | 'image_cropping', 'widget_tweaks', 'macros', 'rest_framework'] 17 | 18 | context_processors = ['colab_edemocracia.processors.recaptcha_site_key', 19 | 'colab_edemocracia.processors.home_customization'] 20 | 21 | settings_variables = { 22 | 'STATICFILES_FINDERS': ( 23 | 'django.contrib.staticfiles.finders.FileSystemFinder', 24 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 25 | 'djangobower.finders.BowerFinder', 26 | 'compressor.finders.CompressorFinder', 27 | ), 28 | 'BOWER_COMPONENTS_ROOT': 29 | '/usr/lib/python2.7/site-packages/colab_edemocracia/static', 30 | 'BOWER_INSTALLED_APPS': ( 31 | 'foundation-sites#6.2.3', 32 | 'jquery-mask-plugin', 33 | 'https://github.com/labhackercd/fontastic-labhacker.git', 34 | ), 35 | 'COMPRESS_PRECOMPILERS': ( 36 | ('text/x-scss', 'django_libsass.SassCompiler'), 37 | ), 38 | 'LIBSASS_SOURCEMAPS': 'DEBUG', 39 | 'COMPRESS_ROOT': "/usr/lib/python2.7/site-packages/colab_edemocracia/static", 40 | 'COMPRESS_NODE_MODULES': "/usr/lib/python2.7/site-packages/colab_edemocracia/node_modules", 41 | "COMPRESS_NODE_SASS_BIN": "/usr/lib/python2.7/site-packages/colab_edemocracia/node_modules/.bin/node-sass", 42 | "COMPRESS_POSTCSS_BIN": "/usr/lib/python2.7/site-packages/colab_edemocracia/node_modules/.bin/postcss", 43 | 'COLAB_TEMPLATES': ( 44 | "/usr/lib/python2.7/site-packages/colab_edemocracia/templates", 45 | ), 46 | 'COLAB_STATICS': [ 47 | '/usr/lib/python2.7/site-packages/colab_edemocracia/static', 48 | '/usr/lib/python2.7/site-packages/colab_edemocracia/templates/components/edem-navigation/static', 49 | ], 50 | 'RECAPTCHA_SITE_KEY': config('RECAPTCHA_SITE_KEY', default=''), 51 | 'RECAPTCHA_PRIVATE_KEY': config('RECAPTCHA_PRIVATE_KEY', default=''), 52 | 'SITE_NAME': config('SITE_NAME', default='Nome do site'), 53 | 'SITE_LOGO': config('SITE_LOGO', default='https://exemple.com/img.png'), 54 | 'COMPRESS_ENABLED': True, 55 | 'COMPRESS_OFFLINE': True, 56 | 'REST_FRAMEWORK': { 57 | 'DEFAULT_RENDERER_CLASSES': ( 58 | 'rest_framework.renderers.JSONRenderer', 59 | ), 60 | 'PAGE_SIZE': 20 61 | }, 62 | } 63 | -------------------------------------------------------------------------------- /misc/etc/colab/plugins.d/tos.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | name = 'colab_mkdocs_tos' 4 | verbose_name = 'Colab Mkdocs Plugin Plugin' 5 | 6 | upstream = '' 7 | 8 | docs_title = "Sobre" 9 | 10 | pages = [ 11 | ('Página Inicial', 'index.md'), 12 | ('Wikilegis', 'wikilegis.md'), 13 | ('Audiências Interativas', 'audiencias.md'), 14 | ('Expressão', 'expressao.md'), 15 | ('Termos de Serviço', 'tos.md'), 16 | ] 17 | 18 | 19 | urls = { 20 | 'include': 'colab_mkdocs_tos.urls', 21 | 'prefix': '^sobre/', 22 | } 23 | -------------------------------------------------------------------------------- /misc/etc/colab/plugins.d/wikilegis.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | name = 'colab_wikilegis' 4 | verbose_name = 'Colab Wikilegis Plugin Plugin' 5 | 6 | upstream = 'http://wikilegisweb:8000/' 7 | 8 | api_key = config('WIKILEGIS_API_KEY') 9 | 10 | urls = { 11 | 'include': 'colab_wikilegis.urls', 12 | 'prefix': '^wikilegis/', 13 | 'login': '/wikilegis/accounts/login/', 14 | } 15 | 16 | settings_variables = { 17 | 'COLAB_STATICS': [ 18 | '/usr/lib/python2.7/site-packages/colab_wikilegis/static' 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /misc/etc/colab/settings.d/01-database.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | 4 | DATABASES = { 5 | 'default': { 6 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 7 | 'HOST': config('DATABASE_HOST', default='127.0.0.1'), 8 | 'NAME': config('DATABASE_NAME', default='colab'), 9 | 'PASSWORD': config('DATABASE_PASSWORD', default=''), 10 | 'USER': config('DATABASE_USER', default='root') 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /misc/etc/colab/settings.d/02-memcached.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | CACHES = { 4 | 'default': { 5 | 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 6 | 'LOCATION': config('MEMCACHED_LOCATION', default='127.0.0.1'), 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /misc/etc/colab/settings.d/03-logging.py: -------------------------------------------------------------------------------- 1 | LOGGING = { 2 | 'version': 1, 3 | 'disable_existing_loggers': True, 4 | 'formatters': { 5 | 'verbose': { 6 | 'format': '%(asctime)s (%(name)s) %(levelname)s: %(message)s' 7 | } 8 | }, 9 | 'handlers': { 10 | 'file': { 11 | 'level': 'DEBUG', 12 | 'interval': 24, 13 | 'backupCount': 7, 14 | 'encoding': 'UTF-8', 15 | 'formatter': 'verbose', 16 | 'class': 'logging.handlers.TimedRotatingFileHandler', 17 | 'filename': '/var/log/colab/colab.log', 18 | } 19 | }, 20 | 'loggers': { 21 | 'revproxy': { 22 | 'handlers': ['file'], 23 | 'level': 'ERROR', 24 | }, 25 | 'django': { 26 | 'handlers': ['file'], 27 | 'level': 'ERROR', 28 | }, 29 | 'colab': { 30 | 'handlers': ['file'], 31 | 'level': 'ERROR', 32 | }, 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /misc/etc/colab/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from decouple import config, Csv 3 | 4 | 5 | DEBUG = config('DEBUG', cast=bool, default=True) 6 | TEMPLATE_DEBUG = config('TEMPLATE_DEBUG', cast=bool, default=True) 7 | 8 | ## System admins 9 | ADMINS = [ 10 | (config('ADMIN_USERNAME', default=''), config('ADMIN_EMAIL', default='')), 11 | ] 12 | 13 | MANAGERS = ADMINS 14 | 15 | # general Django settings 16 | DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', default='') 17 | 18 | # colab-specific 19 | COLAB_FROM_ADDRESS = config('DEFAULT_FROM_EMAIL', default='') 20 | SERVER_EMAIL = config('SERVER_EMAIL', default='') 21 | 22 | EMAIL_HOST = config('EMAIL_HOST', default='') 23 | EMAIL_PORT = config('EMAIL_PORT', cast=int, default=587) 24 | EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='') 25 | EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='') 26 | EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool, default=True) 27 | EMAIL_SUBJECT_PREFIX = config('EMAIL_SUBJECT_PREFIX', default='') 28 | 29 | SECRET_KEY = config('SECRET_KEY', default='secret_key') 30 | 31 | ALLOWED_HOSTS = config('ALLOWED_HOSTS', 32 | cast=Csv(lambda x: x.strip().strip(',').strip()), 33 | default='*') 34 | 35 | ROBOTS_NOINDEX = config('ROBOTS_NOINDEX', cast=bool, default=True) 36 | 37 | ## Set URL of Colab home 38 | COLAB_HOME_URL = '/home' 39 | 40 | LOGIN_URL = COLAB_HOME_URL 41 | 42 | STATIC_ROOT = '/var/labhacker/colab/public/static/' 43 | MEDIA_ROOT = '/var/labhacker/colab/public/media/' 44 | 45 | HAYSTACK_CONNECTIONS = { 46 | 'default': { 47 | 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', 48 | 'URL': 'http://127.0.0.1:9200/', 49 | 'INDEX_NAME': 'haystack', 50 | }, 51 | } 52 | 53 | SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = config('SOCIAL_AUTH_GOOGLE_OAUTH2_KEY', default='') 54 | SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = config('SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET', default='') 55 | 56 | SOCIAL_AUTH_FACEBOOK_KEY = config('SOCIAL_AUTH_FACEBOOK_KEY', default='') 57 | SOCIAL_AUTH_FACEBOOK_SECRET = config('SOCIAL_AUTH_FACEBOOK_SECRET', default='') 58 | 59 | 60 | LANGUAGE_CODE = 'pt-br' 61 | 62 | RIBBON_ENABLED = False 63 | 64 | from easy_thumbnails.conf import Settings as thumbnail_settings 65 | THUMBNAIL_PROCESSORS = ( 66 | 'image_cropping.thumbnail_processors.crop_corners', 67 | ) + thumbnail_settings.THUMBNAIL_PROCESSORS -------------------------------------------------------------------------------- /misc/etc/colab/widgets.d/audiencias_widgets.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import WidgetManager 2 | from colab_audiencias.widgets.home_section import AudienciasHomeSectionWidget 3 | from colab_audiencias.widgets.navigation_links import ( 4 | AudienciasNavigationLinksWidget 5 | ) 6 | 7 | 8 | WidgetManager.register_widget('home_section', AudienciasHomeSectionWidget()) 9 | WidgetManager.register_widget('navigation_links', 10 | AudienciasNavigationLinksWidget()) 11 | -------------------------------------------------------------------------------- /misc/etc/colab/widgets.d/discourse_widgets.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import WidgetManager 2 | from colab_discourse.widgets.home_section import DiscourseHomeSectionWidget 3 | from colab_discourse.widgets.navigation_links import ( 4 | DiscourseNavigationLinksWidget 5 | ) 6 | 7 | 8 | WidgetManager.register_widget('home_section', DiscourseHomeSectionWidget()) 9 | WidgetManager.register_widget('navigation_links', 10 | DiscourseNavigationLinksWidget()) 11 | -------------------------------------------------------------------------------- /misc/etc/colab/widgets.d/wikilegis_widgets.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import WidgetManager 2 | from colab_wikilegis.widgets.home_section import WikilegisHomeSectionWidget 3 | from colab_wikilegis.widgets.navigation_links import ( 4 | WikilegisNavigationLinksWidget 5 | ) 6 | 7 | WidgetManager.register_widget('home_section', WikilegisHomeSectionWidget()) 8 | WidgetManager.register_widget('navigation_links', 9 | WikilegisNavigationLinksWidget()) 10 | -------------------------------------------------------------------------------- /misc/etc/cron.d/colab-audiencias: -------------------------------------------------------------------------------- 1 | * * * * * colab-admin fetch_data_audiencias -------------------------------------------------------------------------------- /misc/etc/cron.d/colab-wikilegis: -------------------------------------------------------------------------------- 1 | */30 * * * * colab-admin fetch_data_wikilegis -------------------------------------------------------------------------------- /misc/etc/nginx/conf.d/colab.conf: -------------------------------------------------------------------------------- 1 | upstream colab { 2 | server colab:8000 fail_timeout=10s; 3 | } 4 | 5 | server { 6 | listen 80; 7 | real_ip_header X-Real-IP; 8 | real_ip_recursive on; 9 | 10 | client_max_body_size 4G; 11 | 12 | location /audiencias/ { 13 | resolver 127.0.0.11 ipv6=off; 14 | proxy_pass $scheme://audienciasweb:8000; 15 | proxy_read_timeout 90; 16 | proxy_connect_timeout 90; 17 | proxy_http_version 1.1; 18 | proxy_set_header Upgrade $http_upgrade; 19 | proxy_set_header Connection "Upgrade"; 20 | proxy_set_header Host $host; 21 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 22 | proxy_redirect off; 23 | 24 | location /audiencias/static/ { 25 | alias /var/labhacker/audiencias/public/; 26 | } 27 | 28 | location /audiencias/media/ { 29 | alias /var/labhacker/audiencias/public/media/; 30 | } 31 | } 32 | 33 | location /static/ { 34 | alias /var/labhacker/colab/public/static/; 35 | } 36 | 37 | location /media/ { 38 | alias /var/labhacker/colab/public/media/; 39 | } 40 | 41 | location / { 42 | proxy_pass $scheme://colab; 43 | proxy_read_timeout 90; 44 | proxy_connect_timeout 90; 45 | proxy_set_header Host $host; 46 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 47 | proxy_redirect off; 48 | 49 | location /wikilegis/static/ { 50 | alias /var/labhacker/wikilegis/wikilegis/public/; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /misc/lib/systemd/system/celerybeat.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Celery beat 3 | PartOf=colab.service 4 | 5 | [Service] 6 | User=colab 7 | PermissionsStartOnly=true 8 | ExecStartPre=/usr/bin/install -d -m 0700 -o colab /var/run/colab 9 | ExecStart=/usr/lib/colab/bin/colab-admin celery beat --pidfile=/var/run/colab/celerybeat.pid --schedule=/var/lib/colab/celery/celereybeat-schedule 10 | Restart=on-failure 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /misc/lib/systemd/system/celeryd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Celery worker 3 | PartOf=colab.service 4 | 5 | [Service] 6 | EnvironmentFile=-/etc/default/celeryd 7 | User=colab 8 | ExecStart=/usr/lib/colab/bin/colab-admin celery worker $CELERYD_OPTS 9 | Restart=on-failure 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /misc/lib/systemd/system/colab.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Colab 3 | Before=celeryd.service celerybeat.service 4 | Requires=celeryd.service celerybeat.service 5 | 6 | [Service] 7 | User=colab 8 | EnvironmentFile=-/etc/sysconfig/colab 9 | PermissionsStartOnly=true 10 | ExecStartPre=/usr/bin/install -d -m 0750 -o colab -g colab /var/lock/colab 11 | ExecStart=/usr/lib/colab/bin/gunicorn colab.wsgi:application --config=/etc/colab/gunicorn.py 12 | Restart=on-failure 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /scripts/remove-all-containers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BASEDIR=$(dirname "$0") 3 | source $BASEDIR/remove-all-volumes.sh 4 | 5 | sudo docker rmi -f $( sudo docker images -q ) # Remove images -------------------------------------------------------------------------------- /scripts/remove-all-volumes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR=$(dirname "$0") 4 | source $BASEDIR/stop-all-containers.sh 5 | 6 | sudo docker volume rm $(sudo docker volume ls -q) -------------------------------------------------------------------------------- /scripts/stop-all-containers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo docker stop $(sudo docker ps -a -q) # Stop containers 3 | sudo docker rm $(sudo docker ps -a -q) # Remove containers -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = **/migrations/*,**/urls.py,colab/conf/plugin_template/,colab/utils/tests/settings_with_syntax_error.py 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | 2 | from setuptools import setup, find_packages 3 | 4 | 5 | REQUIREMENTS = [ 6 | 'Django>=1.7.10,<1.8', 7 | 'django-taggit==0.21.3', 8 | 'pytz==2011n', 9 | 'django-hitcounter==0.1.1', 10 | 'python-social-auth==0.2.21', 11 | 'python-decouple==3.1', 12 | 13 | # Search 14 | 'django-haystack>=2.2, <2.5', 15 | 'Whoosh==2.7.0', 16 | 17 | # revproxy 18 | 'django-revproxy[diazo]==0.9.12', 19 | 20 | # Async Signals 21 | 'celery[redis]>=3.1, <4.0', 22 | 23 | # Acceptance tests 24 | 'selenium>=2.53.1', 25 | 'behave_django<0.4.0', 26 | 27 | ### Move out of colab (as plugins): 28 | 29 | # Deps for super_archives 30 | 'etiquetando==0.1', 31 | 'django-taggit>=0.12.1', 32 | 'html2text>=3.200.3', 33 | 'chardet>=2.3.0', 34 | 'urllib3==1.16', 35 | 'requests==2.11.0' 36 | ] 37 | 38 | TEST_REQUIREMENTS = [ 39 | 'coverage>=3.7.1', 40 | 'coveralls>=0.5', 41 | 'flake8>=2.3.0', 42 | 'mock==1.0.1', 43 | ] 44 | 45 | 46 | EXCLUDE_FROM_PACKAGES = [] 47 | 48 | 49 | setup( 50 | name='colab', 51 | version='1.13.5', 52 | url='https://github.com/colab-community/colab', 53 | author='Sergio Oliveira', 54 | author_email='sergio@tracy.com.br', 55 | description='Collaboration platform for communities', 56 | license='LICENSE.txt', 57 | packages=find_packages(exclude=EXCLUDE_FROM_PACKAGES), 58 | include_package_data=True, 59 | entry_points={'console_scripts': [ 60 | 'colab-admin = colab.utils.runner:execute_from_command_line', 61 | ]}, 62 | zip_safe=False, 63 | long_description=open('README.rst').read(), 64 | install_requires=REQUIREMENTS, 65 | tests_require=TEST_REQUIREMENTS, 66 | test_suite="tests.run.runtests", 67 | classifiers=[ 68 | 'Development Status :: 3 - Alpha', 69 | 'Environment :: Web Environment', 70 | 'Framework :: Django', 71 | 'Intended Audience :: Developers', 72 | 'Operating System :: OS Independent', 73 | 'Programming Language :: Python', 74 | 'Programming Language :: Python :: 2', 75 | 'Programming Language :: Python :: 2.7', 76 | 'Topic :: Internet :: WWW/HTTP', 77 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 78 | 'Topic :: Internet :: WWW/HTTP :: WSGI', 79 | ], 80 | ) 81 | -------------------------------------------------------------------------------- /start-colab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PLUGINS_SETTINGS="/etc/colab/plugins.d/" 4 | if [ "$(ls -A $PLUGINS_SETTINGS)" ]; then 5 | find $PLUGINS_SETTINGS ! -name 'edemocracia.py' ! -name 'tos.py' -type f -exec rm -f {} + 6 | fi 7 | 8 | PLUGINS_WIDGETS="/etc/colab/widgets.d/" 9 | if [ "$(ls -A $PLUGINS_WIDGETS)" ]; then 10 | rm /etc/colab/widgets.d/* 11 | fi 12 | 13 | activate_plugin() { 14 | PLUGIN_NAME=$1 15 | cp ./misc/etc/colab/plugins.d/${PLUGIN_NAME}.py /etc/colab/plugins.d/ 16 | cp ./misc/etc/colab/widgets.d/${PLUGIN_NAME}_widgets.py /etc/colab/widgets.d/ 17 | cp ./misc/etc/cron.d/colab-${PLUGIN_NAME} /etc/cron.d/ 18 | crontab /etc/cron.d/colab-${PLUGIN_NAME} 19 | } 20 | 21 | [[ -z "${ENABLE_AUDIENCIAS}" ]] && ENABLE_AUDIENCIAS=2 || ENABLE_AUDIENCIAS="${ENABLE_AUDIENCIAS}" 22 | [[ -z "${ENABLE_WIKILEGIS}" ]] && ENABLE_WIKILEGIS=2 || ENABLE_WIKILEGIS="${ENABLE_WIKILEGIS}" 23 | [[ -z "${ENABLE_DISCOURSE}" ]] && ENABLE_DISCOURSE=2 || ENABLE_DISCOURSE="${ENABLE_DISCOURSE}" 24 | 25 | if [[ "$ENABLE_WIKILEGIS" = true ]]; then 26 | activate_plugin wikilegis 27 | fi 28 | 29 | if [[ "$ENABLE_AUDIENCIAS" = true ]]; then 30 | activate_plugin audiencias 31 | fi 32 | 33 | if [[ "$ENABLE_DISCOURSE" = true ]]; then 34 | activate_plugin discourse 35 | fi 36 | 37 | crond 38 | 39 | while true; do 40 | PG_STATUS=`PGPASSWORD=$DATABASE_PASSWORD psql -U $DATABASE_USER -w -h $DATABASE_HOST -c '\l \q' | grep postgres | wc -l` 41 | if ! [ "$PG_STATUS" -eq "0" ]; then 42 | break 43 | fi 44 | echo "Waiting Database Setup" 45 | sleep 10 46 | done 47 | 48 | PGPASSWORD=$DATABASE_PASSWORD psql -U $DATABASE_USER -w -h $DATABASE_HOST -c "CREATE DATABASE ${DATABASE_NAME} OWNER ${DATABASE_USER}" 49 | colab-admin migrate 50 | colab-admin initdb 51 | 52 | colab-admin bower_install --allow-root 53 | colab-admin compress --force 54 | colab-admin collectstatic --noinput 55 | 56 | gunicorn colab.wsgi:application --config=/etc/colab/gunicorn.py -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/tests/__init__.py -------------------------------------------------------------------------------- /tests/colab_settings.py: -------------------------------------------------------------------------------- 1 | 2 | ## Set to false in production 3 | DEBUG = True 4 | TEMPLATE_DEBUG = False 5 | 6 | ## System admins 7 | ADMINS = [['John Foo', 'john@example.com'], ['Mary Bar', 'mary@example.com']] 8 | 9 | MANAGERS = ADMINS 10 | 11 | COLAB_FROM_ADDRESS = '"Colab" ' 12 | SERVER_EMAIL = '"Colab" ' 13 | 14 | EMAIL_HOST = 'localhost' 15 | EMAIL_PORT = 25 16 | EMAIL_SUBJECT_PREFIX = '[colab]' 17 | 18 | SECRET_KEY = 'not-a-secret' 19 | 20 | ALLOWED_HOSTS = [ 21 | 'localhost', 22 | # 'example.com', 23 | # 'example.org', 24 | # 'example.net', 25 | ] 26 | 27 | ### Uncomment to enable social networks fields profile 28 | SOCIAL_NETWORK_ENABLED = True 29 | 30 | ## Disable indexing 31 | ROBOTS_NOINDEX = True 32 | 33 | LOGGING = { 34 | 'version': 1, 35 | 36 | 'handlers': { 37 | 'null': { 38 | 'level': 'DEBUG', 39 | 'class': 'logging.NullHandler', 40 | }, 41 | }, 42 | 43 | 'loggers': { 44 | 'colab.mailman': { 45 | 'handlers': ['null'], 46 | 'propagate': False, 47 | }, 48 | 'haystack': { 49 | 'handlers': ['null'], 50 | 'propagate': False, 51 | }, 52 | }, 53 | } 54 | 55 | STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' 56 | 57 | from colab.settings import INSTALLED_APPS 58 | 59 | INSTALLED_APPS += ('behave_django', ) 60 | 61 | BLACKLIST = [r'^test_blacklist$'] 62 | -------------------------------------------------------------------------------- /tests/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | 6 | os.environ['DJANGO_SETTINGS_MODULE'] = 'colab.settings' 7 | os.environ['COLAB_SETTINGS'] = 'tests/colab_settings.py' 8 | os.environ['COLAB_SETTINGS_DIR'] = 'tests/settings.d' 9 | os.environ['COLAB_WIDGETS_SETTINGS'] = 'tests/widgets_settings.py' 10 | os.environ['COLAB_PLUGINS'] = 'tests/plugins.d' 11 | os.environ['COLAB_WIDGETS'] = 'tests/widgets.d' 12 | os.environ['COVERAGE_PROCESS_START'] = '.coveragerc' 13 | 14 | import coverage 15 | 16 | # Needs to come before the settings import, because some settings instantiate 17 | # objetcs. If they are executed before the coverage startup, those lines 18 | # won't be covered. 19 | if os.path.exists('.coverage'): 20 | os.remove('.coverage') 21 | coverage.process_startup() 22 | 23 | import django 24 | from django.conf import settings 25 | from django.test.utils import get_runner 26 | import colab.settings 27 | 28 | 29 | def runtests(test_suites=[]): 30 | if django.VERSION >= (1, 7, 0): 31 | django.setup() 32 | 33 | test_runner = get_runner(settings) 34 | failures = test_runner(interactive=False, failfast=False).run_tests( 35 | test_suites) 36 | sys.exit(failures) 37 | 38 | 39 | if __name__ == '__main__': 40 | all_valid_apps = True 41 | 42 | for arg in sys.argv[1:]: 43 | if arg not in colab.settings.INSTALLED_APPS: 44 | print arg + " App not found" 45 | print "Try colab." + arg 46 | all_valid_apps = False 47 | 48 | if all_valid_apps: 49 | runtests(sys.argv[1:]) 50 | -------------------------------------------------------------------------------- /tests/settings.d/settings.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labhackercd/edemocracia-colab/1d252a3e3b3a9ed73f92ef192b2dfd2fea70c623/tests/settings.d/settings.py -------------------------------------------------------------------------------- /tests/widgets.d/charts_widget.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import WidgetManager 2 | from colab.accounts.widgets.collaboration_chart import CollaborationChart 3 | 4 | WidgetManager.register_widget('charts', CollaborationChart()) 5 | -------------------------------------------------------------------------------- /tests/widgets.d/dashboard_widget.py: -------------------------------------------------------------------------------- 1 | from colab.widgets.widget_manager import WidgetManager 2 | from colab.widgets.dashboard.dashboard_latest_collaborations import DashboardLatestCollaborationsWidget 3 | from colab.widgets.dashboard.dashboard_collaboration_graph import DashboardCollaborationGraphWidget 4 | 5 | 6 | WidgetManager.register_widget( 7 | 'dashboard', DashboardLatestCollaborationsWidget()) 8 | WidgetManager.register_widget( 9 | 'dashboard', DashboardCollaborationGraphWidget()) 10 | -------------------------------------------------------------------------------- /vagrant/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | for dir in /vagrant/colab /vagrant; do 6 | if [ -f $dir/setup.py ]; then 7 | basedir="$dir" 8 | break 9 | fi 10 | done 11 | 12 | # very simple OS detection 13 | if [ -x /usr/bin/apt-get ]; then 14 | exec $basedir/vagrant/ubuntu.sh 15 | fi 16 | if [ -x /usr/bin/yum ]; then 17 | exec $basedir/vagrant/centos.sh 18 | fi 19 | -------------------------------------------------------------------------------- /vagrant/centos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | ### Disable annoying plugin 6 | sed -i'' s/enabled=1/enabled=0/g /etc/yum/pluginconf.d/fastestmirror.conf 7 | 8 | 9 | if [ -n "$http_proxy" ]; then 10 | # force all repositories to always use the same host to take advantage of a 11 | # local proxy 12 | repos=$(grep -rl '^#baseurl' /etc/yum.repos.d) 13 | if [ -n "$repos" ]; then 14 | sed -i -e 's/^#baseurl/baseurl/; s/^mirrorlist=/#mirrorlist-/' $repos 15 | fi 16 | fi 17 | 18 | 19 | ### Install dependencies 20 | 21 | yum install -y epel-release 22 | 23 | yum -y groupinstall "Development tools" 24 | 25 | yum install -y git unzip gettext libxml2-devel libxslt-devel libjpeg-devel32 libjpeg-devel openssl-devel libffi-devel python-devel python-pip python-virtualenvwrapper redis nodejs 26 | 27 | ### Acceptance Tests dependencies 28 | 29 | yum install -y Xvfb firefox 30 | 31 | ### Init Redis 32 | systemctl enable redis 33 | systemctl start redis 34 | -------------------------------------------------------------------------------- /vagrant/misc/etc/default/celerybeat: -------------------------------------------------------------------------------- 1 | # Absolute or relative path to the 'celery' command: 2 | CELERY_BIN="/home/vagrant/.virtualenvs/colab/bin/celery" 3 | 4 | # App instance to use 5 | # comment out this line if you don't use an app 6 | CELERY_APP="colab.celery:app" 7 | 8 | # Where to chdir at start. 9 | CELERYBEAT_CHDIR="/vagrant/" 10 | 11 | # Extra arguments to celerybeat 12 | CELERYBEAT_OPTS="--schedule=/var/run/celery/celerybeat-schedule" 13 | 14 | CELERTBEAT_LOG_FILE="/var/log/celery/beat.log" 15 | CELERYBEAT_PID_FILE="/var/run/celery/beat.pid" 16 | 17 | CELERYBEAT_USER="vagrant" 18 | CELERYBEAT_GROUP="vagrant" 19 | 20 | # If enabled pid and log directories will be created if missing, 21 | # and owned by the userid/group configured. 22 | CELERY_CREATE_DIRS=1 23 | -------------------------------------------------------------------------------- /vagrant/misc/etc/default/celeryd: -------------------------------------------------------------------------------- 1 | # Names of nodes to start 2 | CELERYD_NODES="worker1" 3 | 4 | # Absolute or relative path to the 'celery' command: 5 | CELERY_BIN="/home/vagrant/.virtualenvs/colab/bin/celery" 6 | 7 | # comment out this line if you don't use an app 8 | CELERY_APP="colab.celery:app" 9 | 10 | # Where to chdir at start. 11 | CELERYD_CHDIR="/vagrant/" 12 | 13 | # Extra command-line arguments to the worker 14 | CELERYD_OPTS="--time-limit=300 --concurrency=2" 15 | 16 | # %N will be replaced with the first part of the nodename. 17 | CELERYD_LOG_FILE="/var/log/celery/%N.log" 18 | CELERYD_PID_FILE="/var/run/celery/%N.pid" 19 | 20 | # Workers should run as an unprivileged user. 21 | # You need to create this user manually (or you can choose 22 | # a user/group combination that already exists, e.g. nobody). 23 | CELERYD_USER="vagrant" 24 | CELERYD_GROUP="vagrant" 25 | 26 | # If enabled pid and log directories will be created if missing, 27 | # and owned by the userid/group configured. 28 | CELERY_CREATE_DIRS=1 29 | -------------------------------------------------------------------------------- /vagrant/misc/etc/init.d/solr: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # chkconfig: 2345 95 20 3 | # description: Solr 4 | # processname: myscript 5 | # 6 | #----------------------------------------------------- 7 | # Script for running solr as a service. 8 | # 9 | # Usage: service solr {start|stop|restart|status}" 10 | # 11 | #----------------------------------------------------- 12 | # This should be placed in /etc/init.d 13 | 14 | . /etc/rc.d/init.d/functions 15 | 16 | # Path to pid file 17 | PIDFILE=/var/run/solr.pid 18 | 19 | # Service name 20 | NAME="Solr" 21 | 22 | # Service description 23 | DESC="start/stop Solr Server" 24 | 25 | SOLR_INIT="/home/vagrant/solr-4.10.3/start.sh" 26 | 27 | case $1 in 28 | start) 29 | action "Starting ${NAME}: " daemon --pidfile $PIDFILE $SOLR_INIT 30 | ;; 31 | stop) 32 | action "Stopping ${NAME}: " killproc -p $PIDFILE 33 | ;; 34 | restart) 35 | $0 stop 36 | $0 start 37 | ;; 38 | status) 39 | status -p $PIDFILE solr 40 | ;; 41 | *) 42 | echo "Usage: $0 {start|stop|restart|status}" 43 | exit 3 44 | ;; 45 | esac 46 | -------------------------------------------------------------------------------- /vagrant/provision.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | ### Configure Colab 6 | export VIRTUALENVWRAPPER_PYTHON="/usr/bin/python2.7" 7 | 8 | set +e 9 | if [ -f /usr/local/bin/virtualenvwrapper.sh ]; then 10 | source /usr/local/bin/virtualenvwrapper.sh 11 | elif [ -f /usr/share/virtualenvwrapper/virtualenvwrapper.sh ]; then 12 | source /usr/share/virtualenvwrapper/virtualenvwrapper.sh 13 | else 14 | source /usr/bin/virtualenvwrapper.sh 15 | fi 16 | 17 | if [ ! -d /home/vagrant/.virtualenvs/colab ]; then 18 | mkvirtualenv colab 19 | fi 20 | 21 | workon colab 22 | pip install --upgrade setuptools 23 | 24 | set -e 25 | 26 | for dir in /vagrant/colab /vagrant; do 27 | if [ -f $dir/setup.py ]; then 28 | basedir="$dir" 29 | break 30 | fi 31 | done 32 | pip install -e $basedir 33 | 34 | ### Create conf directory 35 | sudo mkdir -p /etc/colab/widgets.d 36 | sudo mkdir -p /etc/colab/plugins.d 37 | sudo chown -R vagrant:vagrant /etc/colab 38 | 39 | if [ ! -s /etc/colab/settings.py ]; then 40 | colab-admin initconfig > /etc/colab/settings.py 41 | rm -f /etc/colab/settings.pyc # remove pyc if exists 42 | fi 43 | 44 | # colab-admin migrate 45 | 46 | # Init.d Celery files 47 | sudo cp $basedir/vagrant/misc/etc/init.d/celery* /etc/init.d/ 48 | sudo cp $basedir/vagrant/misc/etc/default/celery* /etc/default/ 49 | sudo service celeryd stop || echo 50 | sudo service celerybeat stop || echo 51 | sleep 2 52 | sudo service celeryd start 53 | sudo service celerybeat start 54 | 55 | PLUGINS_DIR=/colab-plugins 56 | 57 | if [ ! -d "$PLUGINS_DIR/edemocracia" ]; then 58 | git clone https://github.com/labhackercd/colab-edemocracia-plugin.git $PLUGINS_DIR/edemocracia 59 | pip install -e $PLUGINS_DIR/edemocracia 60 | ln -s $PLUGINS_DIR/edemocracia/etc/colab/plugins.d/edemocracia.py /etc/colab/plugins.d/edemocracia.py 61 | fi 62 | 63 | sudo npm install -g bower 64 | colab-admin bower_install -------------------------------------------------------------------------------- /vagrant/solr/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Directory where solr is installed 4 | SOLR_HOME=/home/vagrant/solr-4.10.3/example 5 | 6 | # Java options for Solr 7 | OPTIONS="-Xmx128m" 8 | 9 | # Path to pid file 10 | PIDFILE=/var/run/solr.pid 11 | 12 | # Path to log file 13 | LOG_FILE=/var/log/solr.log 14 | 15 | COMMAND="java $OPTIONS -jar start.jar" 16 | 17 | cd $SOLR_HOME 18 | nohup $COMMAND > $LOG_FILE 2>&1 & 19 | echo $! > $PIDFILE 20 | exit $? 21 | -------------------------------------------------------------------------------- /vagrant/ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | ### Install dependencies 6 | apt-get update 7 | 8 | apt-get install curl git unzip build-essential libjpeg-dev gettext libxml2-dev libxslt1-dev libssl-dev libffi-dev python-dev virtualenvwrapper python-pip redis-server -y 9 | 10 | ### Acceptance Tests dependencies 11 | 12 | apt-get install xvfb firefox -y --------------------------------------------------------------------------------