├── .gitignore
├── README.md
├── gamification
├── __init__.py
├── badges
│ ├── __init__.py
│ ├── admin.py
│ ├── badges_notes.txt
│ ├── fixtures
│ │ └── initial_data.json
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto__add_field_projectbadge_awardLevel__add_field_projectbadge_multip.py
│ │ ├── 0003_auto__chg_field_badge_icon.py
│ │ ├── 0004_auto__add_field_projectbadge_tags.py
│ │ └── __init__.py
│ ├── models.py
│ ├── signals.py
│ ├── templates
│ │ └── badges
│ │ │ ├── badge.html
│ │ │ ├── badges_display.html
│ │ │ ├── detail.html
│ │ │ └── overview.html
│ ├── templatetags
│ │ ├── __init__.py
│ │ └── badges_tags.py
│ ├── tests.py
│ ├── urls.py
│ ├── utils.py
│ └── views.py
├── core
│ ├── __init__.py
│ ├── admin.py
│ ├── fixtures
│ │ └── initial_data.json
│ ├── forms.py
│ ├── meta_badges.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_initdata.py
│ │ ├── 0003_auto__add_field_project_viewing_pass_phrase__add_field_project_query_t.py
│ │ ├── 0004_auto__add_team__add_field_project_visual_theme__add_field_project_allo.py
│ │ ├── 0005_auto__add_field_project_background_image.py
│ │ ├── 0006_auto__add_field_project_properties.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── templates
│ │ └── core
│ │ │ ├── 404.json
│ │ │ ├── award.html
│ │ │ ├── badge_list.html
│ │ │ ├── base.html
│ │ │ ├── index.html
│ │ │ ├── master_badge_list.html
│ │ │ ├── masterprojects_list.html
│ │ │ ├── points_list.html
│ │ │ ├── project_admin.html
│ │ │ ├── projects.html
│ │ │ ├── projects_list.html
│ │ │ ├── user_project_points_list.html
│ │ │ └── users.html
│ ├── templatetags
│ │ ├── __init__.py
│ │ └── version.py
│ ├── tests.py
│ ├── urls.py
│ ├── utils.py
│ └── views.py
├── events
│ ├── __init__.py
│ ├── admin.py
│ ├── experimental
│ │ ├── mandatory_training_1.policy
│ │ ├── mandatory_training_2.policy
│ │ ├── rules_engine.py
│ │ └── state.py
│ ├── fixtures
│ │ ├── camp_data.json
│ │ └── initial_data.json
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── state.py
│ └── views.py
├── png.py
├── receivers.py
├── requirements.txt
├── settings.py
├── site_media
│ └── media
│ │ └── badge_images
│ │ ├── bronze.png
│ │ ├── gold.png
│ │ └── silver.png
├── startup.py
├── static
│ ├── README
│ ├── admin
│ │ └── css
│ │ │ └── base.css
│ ├── bootstrap
│ │ ├── css
│ │ │ ├── bootstrap-responsive.css
│ │ │ ├── bootstrap.css
│ │ │ └── bootstrap.min.css
│ │ └── js
│ │ │ ├── bootstrap-dialog.js
│ │ │ └── bootstrap.min.js
│ ├── css
│ │ ├── bootstrap.min.css
│ │ └── project_list.css
│ ├── img
│ │ ├── bronze.png
│ │ ├── gold.png
│ │ ├── silver.png
│ │ └── title.png
│ ├── js
│ │ ├── TimeCircles
│ │ │ ├── TimeCircles.css
│ │ │ └── TimeCircles.js
│ │ ├── jquery.min.js
│ │ ├── maths.js
│ │ ├── moment.min.js
│ │ ├── underscore-min.js
│ │ └── underscore.string.min.js
│ └── themes
│ │ ├── camping
│ │ ├── badges.css
│ │ ├── badges.js
│ │ ├── blue_jersey.png
│ │ ├── canoe_green_sideways.png
│ │ ├── card_wood.png
│ │ ├── card_wood_100.png
│ │ ├── card_wood_150.png
│ │ ├── card_wood_200.png
│ │ ├── card_wood_300.png
│ │ ├── corner_border_brown.png
│ │ ├── corner_border_cyber_blue.png
│ │ ├── oar.png
│ │ ├── paddles.js
│ │ ├── page_background.jpg
│ │ ├── style.css
│ │ ├── test_canvas.html
│ │ └── tinycolor.js
│ │ ├── camping2
│ │ ├── page_background.jpg
│ │ └── style.css
│ │ └── map
│ │ ├── page_background.jpg
│ │ └── style.css
├── templates
│ ├── _account_bar.html
│ ├── _footer.html
│ ├── homepage.html
│ └── site_base.html
├── urls.py
└── wsgi.py
├── manage.py
├── pavement.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | ###
6 | # Ignore Chef key files and secrets
7 | ###
8 | .chef/*.pem
9 | .chef/encrypted_data_bag_secret
10 | .idea
11 | .idea/*
12 | .cache
13 | .cache/*
14 | .vagrant
15 | .vagrant/*
16 | *.swp
17 |
18 | .DS_Store
19 | CACHE/*
20 | *.log
21 | *.pot
22 |
23 | Berksfile.lock
24 | vagrant_dev_settings.yml
25 |
26 | # C extensions
27 | *.so
28 |
29 | # Distribution / packaging
30 | .Python
31 | env/
32 | bin/
33 | build/
34 | develop-eggs/
35 | dist/
36 | eggs/
37 | lib/
38 | lib64/
39 | parts/
40 | sdist/
41 | var/
42 | *.egg-info/
43 | .installed.cfg
44 | *.egg
45 |
46 | # Installer logs
47 | pip-log.txt
48 | pip-delete-this-directory.txt
49 |
50 | # Unit test / coverage reports
51 | htmlcov/
52 | .tox/
53 | .coverage
54 | .cache
55 | nosetests.xml
56 | coverage.xml
57 |
58 | # Translations
59 | *.mo
60 |
61 | # Mr Developer
62 | .mr.developer.cfg
63 | .project
64 | .pydevproject
65 |
66 | # Rope
67 | .ropeproject
68 |
69 |
70 | # Sphinx documentation
71 | docs/_build/
72 |
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # django-gamification
2 |
3 | #### Django Gamification API ####
4 |
5 | The aim of this project is to create a prototype API for implementing game incentives into an application
6 |
7 | Anyone who would like to change development priorities is welcome to Fork the library. Please submit any proposed fixes or improvements through a Github Pull Request.
8 |
9 | ### django-gamificaiton Configuration ###
10 |
11 | The ``django-gamification/settings.py`` file contains installation-specific settings. The Database name/pw and server URLs will need to be configured here.
12 |
13 |
14 | ### django-gamification Installation ###
15 |
16 |
17 | 1. Make sure Python, Virtualenv, and Git are installed
18 |
19 | 2. Install and setup geoq-django:
20 |
21 | % mkdir -p ~/pyenv
22 | % virtualenv --no-site-packages ~/pyenv/gamification
23 | % source ~/pyenv/gamification/bin/activate
24 | % git clone https://github.com/stephenrjones/django-gamification
25 |
26 | 3. Create the database and sync dependencies and data
27 |
28 | % cd django-gamification
29 | % pip install paver
30 | % paver install_dependencies
31 | % paver createdb
32 | % paver create_db_user
33 | % paver sync
34 |
35 |
36 | 4. Build user accounts:
37 |
38 | % python manage.py createsuperuser
39 |
40 |
41 | 9. Start it up!
42 |
43 | % python manage.py runserver
44 |
45 |
46 | ### License ###
47 | MIT license
48 |
49 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, as long as any reuse or further development of the software attributes the authorship as follows: 'This software (django-gamification) is provided to the public as a courtesy of the National Geospatial-Intelligence Agency.
50 |
51 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
52 |
53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54 |
55 |
56 | ### TODOs ###
57 | Current next development goals are tracked as Issues within GitHub, and high-level goals are in ```django-gamification/TODO.rst```.
58 |
--------------------------------------------------------------------------------
/gamification/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from gamification.core.models import Points
4 | from gamification.badges.utils import MetaBadge
5 | from gamification.badges.models import ProjectBadge
6 |
7 | def check_points(self,instance):
8 | return False
9 |
10 | def create_badge_classes():
11 | pbadges = ProjectBadge.objects.all()
12 |
13 | for pbadge in pbadges:
14 | cls = type(pbadge.name.encode('ascii','ignore'),(MetaBadge,),{'id':badge.id,'name':badge.name,'model':Points,'level':badge.level,'check_points':check_points})
15 |
16 | # create_badge_classes()
17 |
18 |
19 |
--------------------------------------------------------------------------------
/gamification/badges/__init__.py:
--------------------------------------------------------------------------------
1 | from utils import registered_badges, MetaBadge
2 |
--------------------------------------------------------------------------------
/gamification/badges/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.contrib import admin
4 | from django import forms
5 | from django.contrib.auth.models import User
6 |
7 | from models import Badge,BadgeSettings, ProjectBadge, ProjectBadgeToUser
8 | from singleton_models.admin import SingletonModelAdmin
9 |
10 | class BadgeAdmin(admin.ModelAdmin):
11 | fields = ('name','level','icon',)
12 | list_display = ('name','level')
13 |
14 |
15 | class ProjectBadgeAdmin(admin.ModelAdmin):
16 | list_display = ('name','description','awardLevel')
17 | fields = ('name','description','project','badge','awardLevel','multipleAwards','tags')
18 |
19 | class BadgeSettingsAdmin(admin.ModelAdmin):
20 | fields = ('awardLevel','multipleAwards')
21 | list_display = ('awardLevel','multipleAwards')
22 |
23 | class ProjectBadgeToUserAdminForm(forms.ModelForm):
24 | class Meta:
25 | model = ProjectBadgeToUser
26 |
27 | def __init__(self, *args, **kwargs):
28 | super(ProjectBadgeToUserAdminForm, self).__init__(*args, **kwargs)
29 | self.fields['user'].queryset = User.objects.order_by('username')
30 |
31 | class ProjectBadgeToUserAdmin(admin.ModelAdmin):
32 | list_display = ('projectbadge','user','created')
33 | form = ProjectBadgeToUserAdminForm
34 |
35 | admin.site.register(Badge, BadgeAdmin)
36 | #admin.site.register(BadgeSettings, BadgeSettingsAdmin)
37 | admin.site.register(ProjectBadge, ProjectBadgeAdmin)
38 | admin.site.register(ProjectBadgeToUser, ProjectBadgeToUserAdmin)
39 |
--------------------------------------------------------------------------------
/gamification/badges/badges_notes.txt:
--------------------------------------------------------------------------------
1 | Pip install django-badges (then cloned due to having to make changes for Django 1.4+)
2 | pip install PIL (un-identified dependency)
3 | Modified models to add metabadge and also add user profile
4 |
5 |
6 | How does this work:
7 |
8 | Django-badges hooks into the save callback for one or more models (in our case, currently the AOI model). Any time an AOI is saved, we currently check:
9 | Is this AOI marked completed + with an assigned analyst.
10 | If so, then that analyst's user profile's score is incremented by BadgeSettings.points
11 | The analyst is marked as eligible to receive a badge for completing an AOI (will check if analyst already has this badge)
12 | It then also checks if the analyst has multiple AOIs in multiple projects (NOTE: may want to first check if analyst has the badge since I think checking for the badge is cheaper than how I'm checking for multiple jobs)
13 |
14 | Menu.html was modified to include the user's current score and badges; clicking on the badges item in the menu will go to the badge page.
15 |
16 | Possible extensions:
17 | 1) Currently, django-badges hooks into the post-save function; as far as I know, this means I cannot determine (from inside this function) what changed in the model, so I don't currently handle if an analyst was awarded points but would have just lost them because an admin "fixed" an AOI to be owned by a different analyst (but I do sort of handle it in the sense that when the analyst does get points, it currently recalculates the score from scratch, because I also can't tell if an AOI was being marked as completed (which should score points) or if a completed AOI was being updated for other reasons (which shouldn't). I considered modifying django-badges to hook into pre-save function which lets me see the fields to be changed, which gives me some ability to potentially identify stuff
18 |
19 | 2) Adding additional badges
20 |
21 | 3) Points for supervisors
22 |
23 | 4) Django-badges has the ability to map images to different badges but they aren't being shown at the moment (this looks like I just need to find / write the css for metal and/or medal classes)
24 |
25 |
26 | 11/19/2013: Installation Notes
27 |
28 | Here's a couple of things I needed to do when I installed the badging stuff into the baseline:
29 |
30 | - A new table (UserProfile) was added to track badge points. This should be created when new users are added to the system,
31 | but records may need to be added for existing users
32 |
33 | - In the settings.py file, I updated MEDIA_ROOT and MEDIA_URL variables so that the badge images could be served out if
34 | running geoq-django from the command line (paver start_django). You'll need to update MEDIA_ROOT for your installation.
35 | A 'static' url was also added to the top-level urls.py file. If you're running geoq-django on a wsgi server,
36 | you won't need these as you'll likely have an image directory setup there. This means you'll also make a change to
37 | the entries in the badges_badge db table for the icon path
--------------------------------------------------------------------------------
/gamification/badges/fixtures/initial_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pk": 1,
4 | "model": "badges.badge",
5 | "fields": {
6 | "icon": "img/bronze.png",
7 | "name": "Bronze",
8 | "level": "1"
9 | }
10 | },
11 | {
12 | "pk": 2,
13 | "model": "badges.badge",
14 | "fields": {
15 | "icon": "img/silver.png",
16 | "name": "Silver",
17 | "level": "2"
18 | }
19 | },
20 | {
21 | "pk": 3,
22 | "model": "badges.badge",
23 | "fields": {
24 | "icon": "img/gold.png",
25 | "name": "Gold",
26 | "level": "3"
27 | }
28 | },
29 | {
30 | "pk": 4,
31 | "model": "badges.projectbadge",
32 | "fields": {
33 | "multipleAwards": true,
34 | "name": "Gold",
35 | "created": "2013-12-12T17:58:15.381Z",
36 | "project": 3,
37 | "awardLevel": 10,
38 | "badge": 3,
39 | "description": "Gold badge"
40 | }
41 | },
42 | {
43 | "pk": 5,
44 | "model": "badges.projectbadge",
45 | "fields": {
46 | "multipleAwards": true,
47 | "name": "Silver",
48 | "created": "2013-12-12T17:58:35.170Z",
49 | "project": 3,
50 | "awardLevel": 5,
51 | "badge": 2,
52 | "description": "Silver award"
53 | }
54 | },
55 | {
56 | "pk": 6,
57 | "model": "badges.projectbadge",
58 | "fields": {
59 | "multipleAwards": true,
60 | "name": "Bronze",
61 | "created": "2013-12-12T19:24:48.592Z",
62 | "project": 3,
63 | "awardLevel": 1,
64 | "badge": 1,
65 | "description": "Bronze award"
66 | }
67 | },
68 | {
69 | "pk": 7,
70 | "model": "badges.projectbadge",
71 | "fields": {
72 | "multipleAwards": true,
73 | "name": "contributer",
74 | "created": "2014-05-05T17:33:06.034Z",
75 | "project": 4,
76 | "awardLevel": 1,
77 | "badge": 1,
78 | "description": "Contributer to NGA Connect"
79 | }
80 | }
81 | ]
82 |
--------------------------------------------------------------------------------
/gamification/badges/managers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.db import models
4 |
5 | class BadgeManager(models.Manager):
6 | def active(self):
7 | import badges
8 | return self.get_query_set().filter(id__in=badges.registered_badges.keys())
9 |
--------------------------------------------------------------------------------
/gamification/badges/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import datetime
3 | from south.db import db
4 | from south.v2 import SchemaMigration
5 | from django.db import models
6 |
7 |
8 | class Migration(SchemaMigration):
9 |
10 | def forwards(self, orm):
11 | # Adding model 'Badge'
12 | db.create_table(u'badges_badge', (
13 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14 | ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
15 | ('level', self.gf('django.db.models.fields.CharField')(max_length=1)),
16 | ('icon', self.gf('django.db.models.fields.files.ImageField')(max_length=100)),
17 | ))
18 | db.send_create_signal(u'badges', ['Badge'])
19 |
20 | # Adding model 'ProjectBadge'
21 | db.create_table(u'badges_projectbadge', (
22 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
23 | ('project', self.gf('django.db.models.fields.IntegerField')()),
24 | ('badge', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['badges.Badge'])),
25 | ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
26 | ('description', self.gf('django.db.models.fields.TextField')()),
27 | ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
28 | ))
29 | db.send_create_signal(u'badges', ['ProjectBadge'])
30 |
31 | # Adding model 'ProjectBadgeToUser'
32 | db.create_table(u'badges_projectbadgetouser', (
33 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
34 | ('projectbadge', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['badges.ProjectBadge'])),
35 | ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
36 | ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
37 | ))
38 | db.send_create_signal(u'badges', ['ProjectBadgeToUser'])
39 |
40 | # Adding model 'BadgeSettings'
41 | db.create_table(u'badges_badgesettings', (
42 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
43 | ('awardLevel', self.gf('django.db.models.fields.IntegerField')(default=1000)),
44 | ('multipleAwards', self.gf('django.db.models.fields.BooleanField')(default=True)),
45 | ))
46 | db.send_create_signal(u'badges', ['BadgeSettings'])
47 |
48 |
49 | def backwards(self, orm):
50 | # Deleting model 'Badge'
51 | db.delete_table(u'badges_badge')
52 |
53 | # Deleting model 'ProjectBadge'
54 | db.delete_table(u'badges_projectbadge')
55 |
56 | # Deleting model 'ProjectBadgeToUser'
57 | db.delete_table(u'badges_projectbadgetouser')
58 |
59 | # Deleting model 'BadgeSettings'
60 | db.delete_table(u'badges_badgesettings')
61 |
62 |
63 | models = {
64 | u'auth.group': {
65 | 'Meta': {'object_name': 'Group'},
66 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
68 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
69 | },
70 | u'auth.permission': {
71 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
72 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
73 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
74 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
75 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
76 | },
77 | u'auth.user': {
78 | 'Meta': {'object_name': 'User'},
79 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
80 | 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
81 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
82 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
83 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
84 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
85 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
86 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
87 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
88 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
89 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
90 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
91 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
92 | },
93 | u'badges.badge': {
94 | 'Meta': {'object_name': 'Badge'},
95 | 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
96 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
97 | 'level': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
98 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
99 | },
100 | u'badges.badgesettings': {
101 | 'Meta': {'object_name': 'BadgeSettings'},
102 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
103 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
104 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
105 | },
106 | u'badges.projectbadge': {
107 | 'Meta': {'object_name': 'ProjectBadge'},
108 | 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.Badge']"}),
109 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
110 | 'description': ('django.db.models.fields.TextField', [], {}),
111 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
112 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
113 | 'project': ('django.db.models.fields.IntegerField', [], {}),
114 | 'user': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': u"orm['badges.ProjectBadgeToUser']", 'to': u"orm['auth.User']"})
115 | },
116 | u'badges.projectbadgetouser': {
117 | 'Meta': {'object_name': 'ProjectBadgeToUser'},
118 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
119 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
120 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
121 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
122 | },
123 | u'contenttypes.contenttype': {
124 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
125 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
126 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
127 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
128 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
129 | },
130 | }
131 |
132 | complete_apps = ['badges']
--------------------------------------------------------------------------------
/gamification/badges/migrations/0002_auto__add_field_projectbadge_awardLevel__add_field_projectbadge_multip.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import datetime
3 | from south.db import db
4 | from south.v2 import SchemaMigration
5 | from django.db import models
6 |
7 |
8 | class Migration(SchemaMigration):
9 |
10 | def forwards(self, orm):
11 | # Adding field 'ProjectBadge.awardLevel'
12 | db.add_column(u'badges_projectbadge', 'awardLevel',
13 | self.gf('django.db.models.fields.IntegerField')(default=1000),
14 | keep_default=False)
15 |
16 | # Adding field 'ProjectBadge.multipleAwards'
17 | db.add_column(u'badges_projectbadge', 'multipleAwards',
18 | self.gf('django.db.models.fields.BooleanField')(default=True),
19 | keep_default=False)
20 |
21 |
22 | # Renaming column for 'ProjectBadge.project' to match new field type.
23 | db.rename_column(u'badges_projectbadge', 'project', 'project_id')
24 | # Changing field 'ProjectBadge.project'
25 | db.alter_column(u'badges_projectbadge', 'project_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Project']))
26 | # Adding index on 'ProjectBadge', fields ['project']
27 | db.create_index(u'badges_projectbadge', ['project_id'])
28 |
29 |
30 | def backwards(self, orm):
31 | # Removing index on 'ProjectBadge', fields ['project']
32 | db.delete_index(u'badges_projectbadge', ['project_id'])
33 |
34 | # Deleting field 'ProjectBadge.awardLevel'
35 | db.delete_column(u'badges_projectbadge', 'awardLevel')
36 |
37 | # Deleting field 'ProjectBadge.multipleAwards'
38 | db.delete_column(u'badges_projectbadge', 'multipleAwards')
39 |
40 |
41 | # Renaming column for 'ProjectBadge.project' to match new field type.
42 | db.rename_column(u'badges_projectbadge', 'project_id', 'project')
43 | # Changing field 'ProjectBadge.project'
44 | db.alter_column(u'badges_projectbadge', 'project', self.gf('django.db.models.fields.IntegerField')())
45 |
46 | models = {
47 | u'auth.group': {
48 | 'Meta': {'object_name': 'Group'},
49 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
50 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
51 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
52 | },
53 | u'auth.permission': {
54 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
55 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
56 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
57 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
58 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
59 | },
60 | u'auth.user': {
61 | 'Meta': {'object_name': 'User'},
62 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
63 | 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
64 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
65 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
66 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
68 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
69 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
70 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
71 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
72 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
73 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
74 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
75 | },
76 | u'badges.badge': {
77 | 'Meta': {'object_name': 'Badge'},
78 | 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
79 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
80 | 'level': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
81 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
82 | },
83 | u'badges.badgesettings': {
84 | 'Meta': {'object_name': 'BadgeSettings'},
85 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
86 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
87 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
88 | },
89 | u'badges.projectbadge': {
90 | 'Meta': {'object_name': 'ProjectBadge'},
91 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
92 | 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.Badge']"}),
93 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
94 | 'description': ('django.db.models.fields.TextField', [], {}),
95 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
96 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
97 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
98 | 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Project']"}),
99 | 'user': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': u"orm['badges.ProjectBadgeToUser']", 'to': u"orm['auth.User']"})
100 | },
101 | u'badges.projectbadgetouser': {
102 | 'Meta': {'object_name': 'ProjectBadgeToUser'},
103 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
104 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
105 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
106 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
107 | },
108 | u'contenttypes.contenttype': {
109 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
110 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
111 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
112 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
113 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
114 | },
115 | u'core.project': {
116 | 'Meta': {'ordering': "('-created_at',)", 'object_name': 'Project'},
117 | 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
118 | 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
119 | 'description': ('django.db.models.fields.TextField', [], {}),
120 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
121 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
122 | 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
123 | 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
124 | }
125 | }
126 |
127 | complete_apps = ['badges']
--------------------------------------------------------------------------------
/gamification/badges/migrations/0003_auto__chg_field_badge_icon.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import datetime
3 | from south.db import db
4 | from south.v2 import SchemaMigration
5 | from django.db import models
6 |
7 |
8 | class Migration(SchemaMigration):
9 |
10 | def forwards(self, orm):
11 |
12 | # Changing field 'Badge.icon'
13 | db.alter_column(u'badges_badge', 'icon', self.gf('django.db.models.fields.files.ImageField')(max_length=100, null=True))
14 |
15 | def backwards(self, orm):
16 |
17 | # Changing field 'Badge.icon'
18 | db.alter_column(u'badges_badge', 'icon', self.gf('django.db.models.fields.files.ImageField')(default='', max_length=100))
19 |
20 | models = {
21 | u'auth.group': {
22 | 'Meta': {'object_name': 'Group'},
23 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
24 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
25 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
26 | },
27 | u'auth.permission': {
28 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
29 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
30 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
31 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
32 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
33 | },
34 | u'auth.user': {
35 | 'Meta': {'object_name': 'User'},
36 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
37 | 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
38 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
39 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
40 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
42 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
43 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
44 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
45 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
46 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
47 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
48 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
49 | },
50 | u'badges.badge': {
51 | 'Meta': {'object_name': 'Badge'},
52 | 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
53 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
54 | 'level': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
55 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
56 | },
57 | u'badges.badgesettings': {
58 | 'Meta': {'object_name': 'BadgeSettings'},
59 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
60 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
61 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
62 | },
63 | u'badges.projectbadge': {
64 | 'Meta': {'object_name': 'ProjectBadge'},
65 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
66 | 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.Badge']"}),
67 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
68 | 'description': ('django.db.models.fields.TextField', [], {}),
69 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
70 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
71 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
72 | 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Project']"}),
73 | 'user': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': u"orm['badges.ProjectBadgeToUser']", 'to': u"orm['auth.User']"})
74 | },
75 | u'badges.projectbadgetouser': {
76 | 'Meta': {'object_name': 'ProjectBadgeToUser'},
77 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
78 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
79 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
80 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
81 | },
82 | u'contenttypes.contenttype': {
83 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
84 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
85 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
86 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
87 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
88 | },
89 | u'core.project': {
90 | 'Meta': {'ordering': "('-created_at',)", 'object_name': 'Project'},
91 | 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
92 | 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
93 | 'description': ('django.db.models.fields.TextField', [], {}),
94 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
95 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
96 | 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
97 | 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
98 | }
99 | }
100 |
101 | complete_apps = ['badges']
--------------------------------------------------------------------------------
/gamification/badges/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/badges/migrations/__init__.py
--------------------------------------------------------------------------------
/gamification/badges/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from datetime import datetime
4 |
5 | from django.contrib.auth.models import User
6 | from django.core.urlresolvers import reverse
7 | from django.db import models
8 | from django.conf import settings
9 |
10 | from singleton_models.models import SingletonModel
11 | #from gamification.core.models import Project
12 |
13 | from signals import badge_awarded
14 | from managers import BadgeManager
15 |
16 | if hasattr(settings, 'BADGE_LEVEL_CHOICES'):
17 | LEVEL_CHOICES = settings.BADGE_LEVEL_CHOICES
18 | else:
19 | LEVEL_CHOICES = (
20 | ("1", "Bronze"),
21 | ("2", "Silver"),
22 | ("3", "Gold"),
23 | ("4", "Diamond"),
24 | )
25 |
26 | class Badge(models.Model):
27 | name = models.CharField(max_length=255)
28 | level = models.CharField(max_length=1, choices=LEVEL_CHOICES)
29 | icon = models.ImageField(upload_to='badge_images', default='', null=True, blank=True )
30 | value = 1
31 |
32 | objects = BadgeManager()
33 |
34 | @property
35 | def meta_badge(self):
36 | from utils import registered_badges
37 | return registered_badges[self.id]
38 |
39 | @property
40 | def title(self):
41 | return self.name
42 |
43 | @property
44 | def description(self):
45 | return self.meta_badge.description
46 |
47 | def __unicode__(self):
48 | return u"%s" % self.name
49 |
50 | def get_absolute_url(self):
51 | return reverse('badge_detail', kwargs={'slug': self.id})
52 |
53 | class Meta:
54 | verbose_name_plural = "Badge Templates"
55 |
56 |
57 | class ProjectBadge(models.Model):
58 | project = models.ForeignKey('core.Project')
59 | badge = models.ForeignKey('Badge')
60 | user = models.ManyToManyField(User, related_name="badges", through='ProjectBadgeToUser')
61 | name = models.CharField(max_length=255)
62 | description = models.TextField()
63 | created = models.DateTimeField(default=datetime.now)
64 | awardLevel = models.IntegerField(default=1)
65 | multipleAwards = models.BooleanField(default=True)
66 | tags = models.CharField(max_length=400, default='', null=True, blank=True, help_text='Tags associated with this badge. Use a few small words separated by commas.')
67 |
68 | @property
69 | def meta_badge(self):
70 | from utils import registered_badges
71 | return registered_badges[self.id]
72 |
73 | def award_to(self, user):
74 | #has_badge = self in user.badges.all()
75 | #if self.meta_badge.one_time_only and has_badge:
76 | # return False
77 |
78 | ProjectBadgeToUser.objects.create(projectbadge=self, user=user)
79 |
80 | #badge_awarded.send(sender=self.meta_badge, user=user, badge=self)
81 |
82 | #Grr... deprecated for Django 1.4+
83 | #message_template = "You just got the %s Badge!"
84 | #user.message.success(message = message_template % self.title)
85 |
86 | return ProjectBadgeToUser.objects.filter(projectbadge=self, user=user).count()
87 |
88 | def number_awarded(self, user_or_qs=None):
89 | """
90 | Gives the number awarded total. Pass in an argument to
91 | get the number per user, or per queryset.
92 | """
93 | kwargs = {'badge':self}
94 | if user_or_qs is None:
95 | pass
96 | elif isinstance(user_or_qs, User):
97 | kwargs.update(dict(user=user_or_qs))
98 | else:
99 | kwargs.update(dict(user__in=user_or_qs))
100 | return ProjectBadgeToUser.objects.filter(**kwargs).count()
101 |
102 | def __str__(self):
103 | return self.name
104 |
105 | class ProjectBadgeToUser(models.Model):
106 | projectbadge = models.ForeignKey(ProjectBadge)
107 | user = models.ForeignKey(User)
108 | created = models.DateTimeField(default=datetime.now)
109 |
110 | class Meta:
111 | verbose_name_plural = "Awarded Badges"
112 |
113 | class BadgeSettings(models.Model):
114 | awardLevel = models.IntegerField(default=1)
115 | multipleAwards = models.BooleanField(default=True)
116 |
117 | class Meta:
118 | verbose_name_plural = "Badge Settings"
119 |
120 |
--------------------------------------------------------------------------------
/gamification/badges/signals.py:
--------------------------------------------------------------------------------
1 | import django.dispatch
2 |
3 | badge_awarded = django.dispatch.Signal(providing_args=['user', 'badge'])
--------------------------------------------------------------------------------
/gamification/badges/templates/badges/badge.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | This is the html for displaying an individual badge on the site. It expects that
3 | you will pass it a badge object called "badge".
4 |
5 | Here is an example:
6 |
7 | {% for badge in user_profile.user.badges.all %}
8 | {% include "badges/badge.html" %}
9 | {% endfor %}
10 |
11 |
12 | {% endcomment %}
13 |
14 |
15 | {{ badge.title }}
16 |
17 |
--------------------------------------------------------------------------------
/gamification/badges/templates/badges/badges_display.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | This template is for displaying the badges a user has earned next to their name. It
3 | expects that you will pass it a list of badge objects called badges.
4 |
5 | Here is an easy way to do that:
6 |
7 | {% with badges as post.user.badges %}
8 | {% include "badges/badges_display.html %}
9 | {% endwith %}
10 |
11 | {% endcomment %}
12 |
13 |
14 |
15 | {% load badges_tags %}
16 |
17 |
18 | {% if request.user %}
19 | {% for level in request.user|badge_count %}
20 | {% if level.count %}
21 | {{level.count}}  
22 | {% endif %}
23 | {% endfor %}
24 | {% endif %}
25 |
26 |
--------------------------------------------------------------------------------
/gamification/badges/templates/badges/detail.html:
--------------------------------------------------------------------------------
1 | {% extends "badges/overview.html" %}
2 | {% load badges_tags %}
3 | {% load humanize %}
4 |
5 | {% block body %}
6 |
7 |
{% block head_title %}Badge: {{ badge.title }}{% endblock %}
8 |
{{ badge.description }}
9 |
10 | {% for u in users %}
11 | {{ u.username }}
12 | {% empty %}
13 | Nobody has earned this badge!
14 | {% endfor %}
15 |
16 |
17 | {% endblock %}
--------------------------------------------------------------------------------
/gamification/badges/templates/badges/overview.html:
--------------------------------------------------------------------------------
1 | {% extends "site_base.html" %}
2 | {% load badges_tags %}
3 | {% load humanize %}
4 |
5 | {% block container %}
6 |
7 |
{% block head_title %}Badges{% endblock %}
8 |
Contribute to one or more analyst tasks to earn points and badges. Here is a list of the badges, and how many people have earned each one.
9 |
Badges are fun! They're just little reminders that you are awesome ☺
10 |
11 | {% for badge in badges %}
12 |
13 |
14 | {% if badge|is_in:request.user.badges.all %}✔ {% endif %}
15 |
16 |
17 | {% include "badges/badge.html" %}
18 | × {{ badge.user.count|intcomma }}
19 |
20 | {{ badge.description }}
21 |
22 | {% endfor %}
23 |
24 |
25 | {% endblock %}
26 |
27 |
--------------------------------------------------------------------------------
/gamification/badges/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/badges/templatetags/__init__.py
--------------------------------------------------------------------------------
/gamification/badges/templatetags/badges_tags.py:
--------------------------------------------------------------------------------
1 | from django.template import Library
2 | from badges.utils import badge_count
3 | from badges.models import LEVEL_CHOICES, Badge
4 | level_choices = dict(LEVEL_CHOICES)
5 |
6 | register = Library()
7 |
8 | @register.filter
9 | def is_in(value,arg):
10 | return value in arg
11 |
12 | @register.filter
13 | def level_count(badges, level):
14 | return badges.filter(level=level).count()
15 |
16 | @register.filter
17 | def level_title(level):
18 | return level_choices[level]
19 |
20 | @register.filter('badge_count')
21 | def _badge_count(user_or_qs):
22 | bc = badge_count(user_or_qs)
23 | return badge_count(user_or_qs)
24 |
25 | @register.filter
26 | def number_awarded(badge, user_or_qs=None):
27 | return badge.number_awarded(user_or_qs)
28 |
29 | @register.filter
30 | def progress_start(badge):
31 | return badge.meta_badge.progress_start
32 |
33 | @register.filter
34 | def progress_finish(badge):
35 | return badge.meta_badge.progress_finish
36 |
37 | @register.filter
38 | def progress(badge, user):
39 | return badge.meta_badge.get_progress(user)
40 |
41 | @register.filter
42 | def is_in_progress(badge, user):
43 | return 0 < badge.meta_badge.get_progress(user) < progress_finish(badge)
44 |
45 | @register.filter
46 | def progress_percentage(badge, user):
47 | prog = badge.meta_badge.get_progress_percentage(user=user)
48 | return max(min(prog, 100), 0)
49 |
50 | @register.filter
51 | def level_icon(level):
52 | badge = Badge.objects.get(level=level)
53 | return badge.icon.url
--------------------------------------------------------------------------------
/gamification/badges/tests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """
4 | This file demonstrates writing tests using the unittest module. These will pass
5 | when you run "manage.py test".
6 |
7 | Replace this with more appropriate tests for your application.
8 | """
9 |
10 | from django.test import TestCase
11 |
12 |
13 | class SimpleTest(TestCase):
14 | def test_basic_addition(self):
15 | """
16 | Tests that 1 + 1 always equals 2.
17 | """
18 | self.assertEqual(1 + 1, 2)
19 |
--------------------------------------------------------------------------------
/gamification/badges/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.conf.urls.defaults import *
4 |
5 | from badges import views
6 |
7 | urlpatterns = patterns('',
8 | url(r'^$', views.overview, name="badges_overview"),
9 | url(r'^(?P[A-Za-z0-9_-]+)/$', views.detail, name="badge_detail"),
10 | )
--------------------------------------------------------------------------------
/gamification/badges/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.core.urlresolvers import reverse
4 | from django.db import models
5 | from django.db.models.signals import post_save
6 | from django.contrib.auth.models import User
7 |
8 | from models import Badge as BadgeModel
9 | from models import ProjectBadgeToUser, LEVEL_CHOICES
10 |
11 |
12 | class RequiresUserOrProgress(Exception): pass
13 |
14 | registered_badges = {}
15 |
16 | def register(badge):
17 | if badge.id not in registered_badges:
18 | registered_badges[badge.id] = badge()
19 | return badge
20 |
21 | def badge_count(user_or_qs=None):
22 | """
23 | Given a user or queryset of users, this returns the badge
24 | count at each badge level that the user(s) have earned.
25 |
26 | Example:
27 |
28 | >>> badge_count(User.objects.filter(username='admin'))
29 | [{'count': 0, 'badge__level': '1'}, {'count': 0, 'badge__level': '2'}, {'count': 0, 'badge__level': '3'}, {'count': 0, 'badge__level': '4'}]
30 |
31 | Uses a single database query.
32 | """
33 |
34 | badge_counts = BadgeToUser.objects.all()
35 | if isinstance(user_or_qs, User):
36 | badge_counts = badge_counts.filter(user=user_or_qs)
37 | elif isinstance(user_or_qs, models.query.QuerySet):
38 | badge_counts = badge_counts.filter(user__in=user_or_qs)
39 |
40 | badge_counts = badge_counts.values('badge__level')
41 | badge_counts = badge_counts.annotate(count=models.Count('badge__level'))
42 |
43 | def get_badge_count(level):
44 | bc = [bc for bc in badge_counts if bc['badge__level'] == level]
45 | if bc:
46 | return bc[0]
47 | else:
48 | # if the user has no badges at this level, return the appropriate response
49 | return {'count': 0, 'badge__level': level}
50 |
51 |
52 | return [get_badge_count(level_choice[0]) for level_choice in LEVEL_CHOICES]
53 |
54 | def project_badge_count(user, project, badge_choices, url):
55 | """
56 | Given a user or queryset of users, this returns the badge
57 | count at each badge level that the user(s) have earned.
58 |
59 | Example:
60 |
61 | >>> badge_count(User.objects.filter(username='admin'))
62 | [{'count': 0, 'badge__level': '1'}, {'count': 0, 'badge__level': '2'}, {'count': 0, 'badge__level': '3'}, {'count': 0, 'badge__level': '4'}]
63 |
64 | Uses a single database query.
65 | """
66 |
67 | badges = ProjectBadgeToUser.objects.all()
68 | badge_counts = badges.filter(user=user)
69 |
70 | badge_counts = badge_counts.values('projectbadge__name','projectbadge__badge__icon', 'projectbadge__badge__level', 'projectbadge__description','projectbadge__project__name').order_by('projectbadge__badge__level')
71 | badge_counts = badge_counts.annotate(count=models.Count('projectbadge__name'))
72 |
73 | def get_badge_count(badge):
74 | bc = [bc for bc in badge_counts if bc['projectbadge__name'] == badge.name]
75 | if bc:
76 | # append url path for icon
77 | bc[0]['projectbadge__badge__icon'] = url + bc[0]['projectbadge__badge__icon']
78 | return bc[0]
79 | else:
80 | # if the user has no badges at this level, return the appropriate response
81 | return {'count': 0, 'projectbadge__name': badge.name, 'projectbadge__badge__icon': url + badge.badge.icon.url,
82 | 'level':badge.badge.level, 'projectbadge__description':badge.description, 'projectbadge__project__name':project.name}
83 |
84 | return [get_badge_count(badge) for badge in badge_choices]
85 |
86 | class MetaBadgeMeta(type):
87 |
88 | def __new__(cls, name, bases, attrs):
89 | new_badge = super(MetaBadgeMeta, cls).__new__(cls, name, bases, attrs)
90 | parents = [b for b in bases if isinstance(b, MetaBadgeMeta)]
91 | if not parents:
92 | # If this isn't a subclass of MetaBadge, don't do anything special.
93 | return new_badge
94 | return register(new_badge)
95 |
96 |
97 | class MetaBadge(object):
98 | __metaclass__ = MetaBadgeMeta
99 |
100 | one_time_only = False
101 | model = models.Model
102 |
103 | progress_start = 0
104 | progress_finish = 1
105 |
106 | def __init__(self):
107 | # whenever the server is reloaded, the badge will be initialized and
108 | # added to the database
109 | self._keep_badge_updated()
110 | post_save.connect(self._signal_callback, sender=self.model)
111 |
112 | def _signal_callback(self, **kwargs):
113 | i = kwargs['instance']
114 | self.award_ceremony(i)
115 |
116 | def _test_conditions(self, instance):
117 | condition_callbacks = [getattr(self, c) for c in dir(self) if c.startswith('check')]
118 |
119 | # will return False on the first False condition
120 | return all( fn(instance) for fn in condition_callbacks )
121 |
122 | def get_user(self, instance):
123 | return instance.user
124 |
125 | def get_progress(self, user):
126 | if BadgeToUser.objects.filter(user=user, badge=self.badge).count():
127 | return 1
128 | return 0
129 |
130 | def get_progress_percentage(self, progress=None, user=None):
131 | if user is None and progress is None:
132 | raise RequiresUserOrProgress("This method requires either a user or progress keyword argument")
133 |
134 | if not progress:
135 | progress = self.get_progress(user)
136 |
137 | progress = min(progress, self.progress_finish)
138 |
139 | # multiply by a float to get floating point precision
140 | return (100.0 * progress) / (self.progress_finish - self.progress_start)
141 |
142 | def _keep_badge_updated(self):
143 | if getattr(self, 'badge', False):
144 | return False
145 | badge, created = BadgeModel.objects.get_or_create(id=self.id)
146 | if badge.level != self.level:
147 | badge.level = self.level
148 | badge.save()
149 | self.badge = badge
150 |
151 | def award_ceremony(self, instance):
152 | if self._test_conditions(instance):
153 | user = self.get_user(instance)
154 | self.badge.award_to(user)
155 |
--------------------------------------------------------------------------------
/gamification/badges/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.shortcuts import render_to_response, get_object_or_404
4 | from django.template import RequestContext
5 |
6 | from models import Badge
7 |
8 | def overview(request, extra_context={}):
9 | badges = Badge.objects.active().order_by("level")
10 |
11 | context = locals()
12 | context.update(extra_context)
13 | return render_to_response("badges/overview.html", context, context_instance=RequestContext(request))
14 |
15 | def detail(request, slug, extra_context={}):
16 | badge = get_object_or_404(Badge, id=slug)
17 | users = badge.user.all()
18 |
19 | context = locals()
20 | context.update(extra_context)
21 | return render_to_response("badges/detail.html", context, context_instance=RequestContext(request))
--------------------------------------------------------------------------------
/gamification/core/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
--------------------------------------------------------------------------------
/gamification/core/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | import reversion
27 | from django.shortcuts import render
28 | from django.http import HttpResponseRedirect
29 | from django import forms
30 | from models import Project, UserProfile, Points, Team
31 | from django.contrib import admin
32 |
33 | class ObjectAdmin(admin.ModelAdmin):
34 | list_display = ('name', 'created_at', 'updated_at')
35 |
36 | class UserProfileAdmin(ObjectAdmin):
37 | list_display = ('user','score')
38 |
39 | class PointAdmin(admin.ModelAdmin):
40 | list_display = ('user', 'date_awarded', 'projectbadge', 'value')
41 |
42 | class TeamAdmin(admin.ModelAdmin):
43 | list_display = ('name', 'description', 'date_created')
44 | filter_horizontal = ('members',)
45 |
46 | class ProjectAdmin(admin.ModelAdmin):
47 | model = Project
48 | list_filter = ("private", "active", "visual_theme")
49 | filter_horizontal = ('supervisors', 'teams',)
50 |
51 | normal_fields = ('name', 'private', 'active', 'description', 'visual_theme', 'project_closing_date')
52 | readonly_fields = ('created_at', 'updated_at')
53 |
54 | save_on_top = True
55 | save_as = True
56 |
57 | advanced_fields = ( 'viewing_pass_phrase', 'supervisors', 'teams', 'background_image', 'properties' )
58 | desc = 'The settings below are advanced. Please contact and admin if you have questions.'
59 |
60 | fieldsets = (
61 | (None, {'fields': normal_fields}),
62 | ('Advanced Settings', {'classes': ('collapse',),
63 | 'description': desc,
64 | 'fields': advanced_fields,
65 | }))
66 |
67 |
68 |
69 | admin.site.register(Project, ProjectAdmin)
70 | #admin.site.register(UserProfile, UserProfileAdmin)
71 | admin.site.register(Points, PointAdmin)
72 | admin.site.register(Team, TeamAdmin)
--------------------------------------------------------------------------------
/gamification/core/fixtures/initial_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pk": 3,
4 | "model": "core.project",
5 | "fields": {
6 | "name": "geoq",
7 | "created_at": "2013-12-12T17:57:23.228Z",
8 | "updated_at": "2013-12-12T17:57:23.228Z",
9 | "private": false,
10 | "active": true,
11 | "description": "GeoQ on Django"
12 | }
13 | },
14 | {
15 | "pk": 4,
16 | "model": "core.project",
17 | "fields": {
18 | "name": "ngaconnect",
19 | "created_at": "2014-04-01T18:48:38.278Z",
20 | "updated_at": "2014-04-01T18:48:38.278Z",
21 | "private": false,
22 | "active": true,
23 | "description": "NGA Connect project"
24 | }
25 | }
26 | ]
27 |
--------------------------------------------------------------------------------
/gamification/core/forms.py:
--------------------------------------------------------------------------------
1 | # This technical data was produced for the U. S. Government under Contract No. W15P7T-13-C-F600, and
2 | # is subject to the Rights in Technical Data-Noncommercial Items clause at DFARS 252.227-7013 (FEB 2012)
3 |
4 | from django import forms
5 | from django.contrib.auth.models import User
6 | from gamification.badges.models import ProjectBadge
7 |
8 | class AwardForm(forms.Form):
9 |
10 | award_id = forms.ModelChoiceField(label=(u'Award'),
11 | queryset=ProjectBadge.objects.all(),
12 | required=True)
13 | points = forms.ChoiceField(label=(u'Points to Award'),
14 | widget=forms.Select(),
15 | choices=([('1','1'),('5','5'),('10','10'),('20','20'),('50','50'),]),
16 | required=True)
17 | comment = forms.CharField(label=(u'Comment'),
18 | max_length=255)
--------------------------------------------------------------------------------
/gamification/core/meta_badges.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 | from gamification.core.models import Points
28 | from gamification.badges import MetaBadge
29 |
30 | class Gold(MetaBadge):
31 | id = 1
32 | name = "Gold"
33 | model = Points
34 | one_time_only = False
35 | title = "Gold Award"
36 | level = "1"
37 | def check_project(self,instance):
38 | return False
39 |
40 |
41 | class Silver(MetaBadge):
42 | id = 2
43 | name = "Silver"
44 | model = Points
45 | one_time_only = False
46 | title = "Silver Award"
47 | level = "2"
48 |
49 | def check_project(self, instance):
50 | return False
51 |
52 |
53 | class Bronze(MetaBadge):
54 | id = 3
55 | name = "Bronze"
56 | model = Points
57 | one_time_only = False
58 | title = "Bronze Award"
59 | level = "3"
60 |
61 | def check_project(self, instance):
62 | return False
63 |
--------------------------------------------------------------------------------
/gamification/core/migrations/0002_initdata.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import datetime
3 | from south.db import db
4 | from south.v2 import DataMigration
5 | from django.db import models
6 |
7 | class Migration(DataMigration):
8 |
9 | def forwards(self, orm):
10 | "Write your forwards methods here."
11 | # Note: Don't use "from appname.models import ModelName".
12 | # Use orm.ModelName to refer to models in this application,
13 | # and orm['appname.ModelName'] for models in other applications.
14 |
15 | def backwards(self, orm):
16 | "Write your backwards methods here."
17 |
18 | models = {
19 | u'auth.group': {
20 | 'Meta': {'object_name': 'Group'},
21 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
22 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
23 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
24 | },
25 | u'auth.permission': {
26 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
27 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
28 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
29 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
30 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
31 | },
32 | u'auth.user': {
33 | 'Meta': {'object_name': 'User'},
34 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
35 | 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
36 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
37 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
38 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
39 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
40 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
41 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
42 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
43 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
44 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
45 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
46 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
47 | },
48 | u'badges.badge': {
49 | 'Meta': {'object_name': 'Badge'},
50 | 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
51 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
52 | 'level': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
53 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
54 | },
55 | u'badges.projectbadge': {
56 | 'Meta': {'object_name': 'ProjectBadge'},
57 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
58 | 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.Badge']"}),
59 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
60 | 'description': ('django.db.models.fields.TextField', [], {}),
61 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
62 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
63 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
64 | 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Project']"}),
65 | 'user': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': u"orm['badges.ProjectBadgeToUser']", 'to': u"orm['auth.User']"})
66 | },
67 | u'badges.projectbadgetouser': {
68 | 'Meta': {'object_name': 'ProjectBadgeToUser'},
69 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
70 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
71 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
72 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
73 | },
74 | u'contenttypes.contenttype': {
75 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
76 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
77 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
78 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
79 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
80 | },
81 | u'core.points': {
82 | 'Meta': {'object_name': 'Points'},
83 | 'date_awarded': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
84 | 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
85 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
86 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
87 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
88 | 'value': ('django.db.models.fields.IntegerField', [], {'default': '0'})
89 | },
90 | u'core.project': {
91 | 'Meta': {'ordering': "('-created_at',)", 'object_name': 'Project'},
92 | 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
93 | 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
94 | 'description': ('django.db.models.fields.TextField', [], {}),
95 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
96 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
97 | 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
98 | 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
99 | },
100 | u'core.userprofile': {
101 | 'Meta': {'object_name': 'UserProfile'},
102 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
103 | 'score': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
104 | 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
105 | }
106 | }
107 |
108 | complete_apps = ['core']
109 | symmetrical = True
110 |
--------------------------------------------------------------------------------
/gamification/core/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/core/migrations/__init__.py
--------------------------------------------------------------------------------
/gamification/core/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | import json
27 | from django.contrib.auth.models import User
28 | from django.core.urlresolvers import reverse
29 | from django.utils.datastructures import SortedDict
30 | from django.db.models.signals import post_save
31 | from django.db import models
32 | from gamification.badges.models import ProjectBadge, ProjectBadgeToUser
33 | from jsonfield import JSONField
34 |
35 |
36 | TRUE_FALSE = [(0, 'False'), (1, 'True')]
37 |
38 |
39 | class ProjectBase(models.Model):
40 | """
41 | A generic model for GeoQ objects.
42 | """
43 |
44 | active = models.BooleanField(default=True, help_text='If checked, this project will be listed in the active list.')
45 | created_at = models.DateTimeField(auto_now_add=True)
46 | name = models.CharField(max_length=200, help_text='Name of the project.')
47 | description = models.TextField(help_text='Details of this project that will be listed on the viewing page.')
48 | updated_at = models.DateTimeField(auto_now=True)
49 | url = models.TextField(help_text='Project Information URL', null=True)
50 |
51 | def __unicode__(self):
52 | return self.name
53 |
54 | class Meta:
55 | abstract = True
56 | ordering = ('-created_at',)
57 |
58 |
59 | class Team(models.Model):
60 | name = models.CharField(max_length=50)
61 | description = models.TextField(null=True, blank=True)
62 | members = models.ManyToManyField(User, null=True, blank=True)
63 | order = models.IntegerField(default=0, null=True, blank=True, help_text='Optionally specify the order teams should appear. Lower numbers appear sooner. By default, teams appear in the order they were created.')
64 | date_created = models.DateTimeField(auto_now_add=True)
65 |
66 | background_color = models.CharField(max_length=50, null=True, blank=True, help_text='Optional - Color to use for background of all team badges')
67 | icon = models.ImageField(upload_to='badge_images', null=True, blank=True, help_text='Optional - Image to show next to team names')
68 |
69 | def __str__(self):
70 | return "%s (%s)" % (self.name, str(len(self.members.all())))
71 |
72 | class Meta:
73 | ordering = ['-order', '-date_created', 'id']
74 |
75 |
76 | class Project(ProjectBase):
77 | """
78 | Top-level organizational object.
79 | """
80 |
81 | THEMES = (
82 | ("", "None"),
83 | ("camping", "Camping"),
84 | ("camping2", "Camping Theme 2"),
85 | ("map", "Geospatial"),
86 | )
87 |
88 | private = models.BooleanField(default=False, help_text='If checked, hide this project from the list of projects and public badge APIs.')
89 | supervisors = models.ManyToManyField(User, blank=True, null=True, related_name="supervisors", help_text='Anyone other than site administrators that can add badges and update the site')
90 | teams = models.ManyToManyField(Team, blank=True, null=True)
91 | viewing_pass_phrase = models.CharField(max_length=200, null=True, blank=True, help_text='Phrase that must be entered to view this page.')
92 | project_closing_date = models.DateTimeField(null=True, blank=True, help_text='Date that project "closes" with countdown shown on project page. Badges can still be added after this.')
93 | visual_theme = models.CharField(max_length=20, default="none", choices=THEMES, help_text='Visual Theme used to style the project page')
94 | background_image = models.ImageField(upload_to='badge_images', null=True, blank=True, help_text='Optional - Override theme background with this image')
95 |
96 | properties = JSONField(null=True, blank=True, help_text='JSON key/value pairs associated with this object, e.g. {"badges_mode":"blue"}')
97 |
98 | query_token = models.CharField(max_length=200, null=True, blank=True, help_text='Token that must be entered by any server requesting data - not implemented yet.')
99 | allowed_api_hosts = models.TextField(null=True, blank=True, help_text='Comma-separated list of hosts (IPs or Hostnames) that can access this project via data requests - not implemented yet')
100 |
101 | @property
102 | def user_count(self):
103 | return User.objects.filter(projectbadgetouser__projectbadge__project=self).distinct().count()
104 |
105 | @property
106 | def badge_count(self):
107 | return ProjectBadgeToUser.objects.filter(projectbadge__project=self).count()
108 |
109 | def get_absolute_url(self):
110 | return reverse('project-list', args=[self.name])
111 |
112 | class Points(models.Model):
113 | user = models.ForeignKey(User)
114 | projectbadge = models.ForeignKey(ProjectBadge)
115 | value = models.IntegerField(default=0)
116 | date_awarded = models.DateTimeField('date awarded',auto_now=True)
117 | description = models.CharField(max_length=200)
118 |
119 | def get_absolute_url(self):
120 | return reverse('points-list', args=[self.id])
121 |
122 | class Meta:
123 | verbose_name_plural = "Points"
124 |
125 |
126 | class UserProfile(models.Model):
127 | """ from http://stackoverflow.com/questions/44109/extending-the-user-model-with-custom-fields-in-django; this is one mechanism for adding extra details (currently score for badges) to the User model """
128 | defaultScore = 1
129 | user = models.OneToOneField(User)
130 | score = models.IntegerField(default=defaultScore)
131 |
132 | def __str__(self):
133 | return "%s's profile" % self.user
134 |
135 | def create_user_profile(sender, instance, created, **kwargs):
136 | if created:
137 | profile, created = UserProfile.objects.get_or_create(user=instance)
138 |
139 | post_save.connect(create_user_profile, sender=User)
140 |
141 | import sys
142 | if not 'syncdb' in sys.argv[1:2] and not 'migrate' in sys.argv[1:2]:
143 | from meta_badges import *
--------------------------------------------------------------------------------
/gamification/core/serializers.py:
--------------------------------------------------------------------------------
1 | from django.forms import widgets
2 | from rest_framework import serializers
3 | from models import Project, Points
4 | from django.contrib.auth.models import User
5 |
6 |
7 | class ProjectSerializer(serializers.ModelSerializer):
8 | class Meta:
9 | model = Project
10 | fields = ('id', 'name', 'description', 'created_at', 'active')
11 |
12 | class PointsSerializer(serializers.ModelSerializer):
13 | username = serializers.RelatedField(source='user')
14 | projectbadge_name = serializers.RelatedField(source='projectbadge')
15 |
16 | class Meta:
17 | model = Points
18 | fields = ('username', 'projectbadge_name', 'value', 'date_awarded', 'description')
19 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/404.json:
--------------------------------------------------------------------------------
1 | { "message" : "{{ object.message }}" }
2 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/award.html:
--------------------------------------------------------------------------------
1 | {% extends 'core/base.html' %}
2 |
3 | {% block content %}
4 | Submit Award
5 |
6 |
34 | {% endblock %}
--------------------------------------------------------------------------------
/gamification/core/templates/core/badge_list.html:
--------------------------------------------------------------------------------
1 | {% extends "core/base.html" %}
2 | {% load staticfiles %}
3 | {% block content %}
4 | {% block heading %}
5 |
6 |
13 |
14 |
15 | {% endblock %}
16 |
17 |
18 |
19 |
20 |
21 |
22 | Name
23 | Icon
24 | Description
25 | Points Worth
26 | Can win Multiple?
27 |
28 |
29 |
30 | {% for badge in object_list %}
31 |
32 |
33 | {{ badge.name }}
34 |
35 |
36 | {% with badge_icon=badge.badge__icon %}
37 | {% static badge_icon as badge_url %}
38 |
39 | {% endwith %}
40 |
41 |
42 | {{ badge.description }}
43 |
44 |
45 | {{ badge.awardLevel }}
46 |
47 |
48 | {{ badge.multipleAwards }}
49 |
50 |
51 | {% endfor %}
52 |
53 |
54 |
55 |
56 |
57 |
58 | {% endblock %}
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/base.html:
--------------------------------------------------------------------------------
1 |
2 | {% load bootstrap3 %}
3 | {% load staticfiles %}
4 | {% load version %}
5 |
6 |
7 |
8 |
9 |
10 |
11 | {% block title %}Gamification{% endblock %}
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
36 |
53 |
54 |
55 | {% block container %}
56 |
57 |
58 |
59 |
60 | {% block menu %}
61 |
102 | {% endblock %}
103 |
104 |
105 |
106 | {% block header_title %}
107 | {##}
115 | {% endblock %}
116 |
117 | {% block content %}Empty page{% endblock %}
118 | {% endblock %}
119 |
120 |
121 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/index.html:
--------------------------------------------------------------------------------
1 | {% extends "core/base.html" %}
2 | {% block title %}Gamification Server{% endblock %}
3 | {% load staticfiles %}
4 | {% block content %}
5 |
6 |
7 |
8 |
9 |
Gamification Server
10 |
The Gamification Server is a management tool that allows other web pages, apps, or tools to
11 | utilize "Gamification " concepts. These ideas
12 | have been found to help engage with some users and encourage teamwork. This is a prototype concept used to integrate
13 | tools and test out concepts. Interfaces are available either through this web interface or through a REST-based API
14 | calls.
15 |
The source code for this server is Open Source and currently available on GitHub
16 | and available for anyone to use and improve upon. We encourage your participation and want to hear your ideas!
17 |
18 |
19 |
20 |
21 |
Some of the Badges in various projects
22 | {% for badge in object_list %}
23 | {% with badge_icon=badge.badge__icon %}
24 | {% static badge_icon as badge_url %}
25 |
26 | {% endwith %}
27 | {% endfor %}
28 |
29 |
30 |
31 |
32 | {% endblock %}
--------------------------------------------------------------------------------
/gamification/core/templates/core/master_badge_list.html:
--------------------------------------------------------------------------------
1 | {% extends "core/base.html" %}
2 | {% load staticfiles %}
3 | {% block title %}Badges by project{% endblock %}
4 | {% block content %}
5 | {% block heading %}
6 |
7 | {% endblock %}
8 |
9 |
10 |
11 | {% regroup object_list by project__name as projects %}
12 |
13 | {% for project in projects %}
14 |
15 |
16 |
17 |
18 |
19 | Name
20 | Icon
21 | Description
22 | Tags
23 | Points
24 |
25 |
26 |
27 |
28 | {% for badge in project.list %}
29 |
30 |
31 | {{ badge.name }}
32 |
33 |
34 | {% with badge_icon=badge.badge__icon %}
35 | {% static badge_icon as badge_url %}
36 |
37 | {% endwith %}
38 |
39 |
40 | {{ badge.description }}
41 |
42 |
43 | {{ badge.tags }}
44 |
45 |
46 | {{ badge.awardLevel }}
47 |
48 |
49 | {% endfor %}
50 |
51 |
52 | {% endfor %}
53 |
54 |
55 |
56 |
57 | {% endblock %}
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/masterprojects_list.html:
--------------------------------------------------------------------------------
1 | {% extends "core/base.html" %}
2 |
3 | {% block heading %}
4 |
5 | Project Leaders
6 |
7 | {% endblock %}
8 |
9 |
10 | {% block content %}
11 | {% for project in profile %}
12 | {{ project.description }}
13 | {% for badge in project.badges %}
14 | {{ badge.description }}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | Name
23 | Points Received
24 | Badges Awarded
25 |
26 |
27 |
28 | {% for winner in badge.winners %}
29 |
30 |
31 | {{ winner.user__username }}
32 |
33 |
34 | {{ winner.points_count }}
35 |
36 |
37 | TODO
38 |
39 |
40 | {% endfor %}
41 |
42 |
43 |
44 |
45 |
46 |
47 | {% endfor %}
48 |
49 | {% endfor %}
50 | {% endblock %}
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/points_list.html:
--------------------------------------------------------------------------------
1 | {% extends 'core/base.html' %}
2 | {% block title %}Points for {{ username }}{% endblock %}
3 |
4 | {% block header_title %}
5 |
8 | {% endblock %}
9 |
10 |
11 |
12 | {% block content %}
13 | {% for project in profile %}
14 |
15 |
16 |
{{ project.description }}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Award Name
27 | Points Received
28 | Date
29 | Comment
30 |
31 |
32 |
33 |
34 | {% for badge in project.badges %}
35 | {% if badge.total %}
36 | {% for award in badge.awarded %}
37 |
38 |
39 | {{ badge.name }}
40 |
41 |
42 | {{ award.value }}
43 |
44 |
45 | {{ award.date_awarded|date:"SHORT_DATE_FORMAT" }} at {{ award.date_awarded|time:"H:i" }}
46 |
47 |
48 | {{ award.description }}
49 |
50 |
51 | {% endfor %}
52 | {# #}
53 | {#
#}
54 | {#
{{ badge.total }} {{ badge.name }} Points Accumulated #}
55 | {# #}
56 | {#
#}
57 | {# #}
58 | {% endif %}
59 | {% endfor %}
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Submit Award
68 |
69 |
70 |
71 |
72 |
73 | {% endfor %}
74 | {% endblock %}
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/project_admin.html:
--------------------------------------------------------------------------------
1 | {% extends 'core/base.html' %}
2 |
3 | {% block header_title %}
4 |
7 | {% endblock %}
8 |
9 | {% block content %}
10 |
11 | {% if project.visual_theme %}
12 |
13 | {% endif %}
14 |
15 |
33 |
34 | {% if admin %}
35 |
36 |
65 |
66 | {# Edit Project Info #}
67 | {# TODO: Add Form and edit all project details #}
68 | {# #}
69 | {# #}
70 | {# Ending Date#}
71 |
72 |
73 |
74 | Assign a badge to a user:
75 | {# Add Form #}
76 |
77 | {% for badge in badges %}
78 | {{ badge.name }}
79 | {% endfor %}
80 |
81 |
82 |
83 | {% for user in all_users %}
84 | {{ user.username }}
85 | {% endfor %}
86 |
87 |
88 |
89 | Edit badge assignments manually
90 | Edit badges
91 |
92 |
93 |
94 | Create a new user
95 | Username (one word):
96 | (then push 'POST' on bottom to create)
97 |
98 | {% if project.project_closing_date %}
99 |
100 |
101 |
102 |
103 |
104 | {% endif %}
105 |
106 | {% else %}
107 | Access Denied - You need admin access to this project
108 |
109 | {% endif %}
110 |
111 | {% endblock %}
--------------------------------------------------------------------------------
/gamification/core/templates/core/projects.html:
--------------------------------------------------------------------------------
1 | {% extends "core/base.html" %}
2 | {% block title %}Gamification Projects{% endblock %}
3 | {% block content %}
4 |
5 |
6 |
7 |
8 |
9 |
10 | Project Name
11 | Project Description
12 | Created
13 | Leaderboard
14 | Badges Given
15 | Badge Recipients
16 |
17 |
18 |
19 | {% for project in active_projects %}
20 |
21 |
22 | {{ project.name|title }}
23 |
24 |
25 | {{ project.description }}
26 |
27 |
28 | {{ project.created_at|date:"SHORT_DATE_FORMAT" }}
29 |
30 |
31 |
32 |
33 |
34 | {{ project.badge_count }}
35 |
36 |
37 | {{ project.user_count }}
38 |
39 |
40 | {% endfor %}
41 |
42 |
43 |
44 |
45 |
46 | {% if non_active_projects %}
47 |
48 |
49 |
50 |
51 | Inactive Project
52 | Project Description
53 | Created
54 | Badges Given
55 | Badge Recipients
56 |
57 |
58 |
59 | {% for project in non_active_projects %}
60 |
61 |
62 | {{ project.name|title }}
63 |
64 |
65 | {{ project.description }}
66 |
67 |
68 | {{ project.created_at|date:"SHORT_DATE_FORMAT" }}
69 |
70 |
71 | {{ project.badge_count }}
72 |
73 |
74 | {{ project.user_count }}
75 |
76 |
77 | {% endfor %}
78 |
79 |
80 |
81 | {% endif %}
82 |
83 |
84 |
85 |
86 |
87 | {% endblock %}
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/user_project_points_list.html:
--------------------------------------------------------------------------------
1 | {% extends 'core/base.html' %}
2 |
3 | {% block heading %}
4 |
5 | {% endblock %}
6 |
7 |
8 | {% block content %}
9 |
16 | {% for badge in projectbadges %}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Award Name
25 | Points Received
26 | Date
27 | Comment
28 |
29 |
30 |
31 | {% for award in badge.awarded %}
32 |
33 |
34 | {{ badge.name }}
35 |
36 |
37 | {{ award.value }}
38 |
39 |
40 | {{ award.date_awarded|date:"SHORT_DATE_FORMAT" }} at {{ award.date_awarded|time:"H:i" }}
41 |
42 |
43 | {{ award.description }}
44 |
45 |
46 | {% endfor %}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
Total Points: {{ badge.total }}
54 |
55 |
56 |
57 |
58 |
59 | {% endfor %}
60 |
61 | {% endblock %}
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/gamification/core/templates/core/users.html:
--------------------------------------------------------------------------------
1 | {% extends "core/base.html" %}
2 | {% block content %}
3 | {% block heading %}
4 |
5 |
12 |
13 |
14 | {% endblock %}
15 |
16 |
17 |
18 |
19 |
20 |
21 | Last Name
22 | First Name
23 | Login
24 | Email
25 | Points
26 |
27 |
28 |
29 | {% for user in object_list %}
30 |
31 |
32 | {{ user.last_name }}
33 |
34 |
35 | {{ user.first_name }}
36 |
37 |
38 | {{ user.username }}
39 |
40 |
41 | {{ user.email }}
42 |
43 |
44 |
45 |
46 |
47 | {% endfor %}
48 |
49 |
50 |
51 |
52 |
53 |
54 | {% endblock %}
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/gamification/core/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
--------------------------------------------------------------------------------
/gamification/core/templatetags/version.py:
--------------------------------------------------------------------------------
1 | from django import template
2 | import time
3 | import os
4 |
5 | register = template.Library()
6 |
7 | @register.simple_tag
8 | def version_date():
9 | try:
10 | timestamp = "Updated: " + time.strftime('%m/%d/%Y', time.gmtime(os.path.getmtime('.git')))
11 | except:
12 | timestamp = ""
13 | return timestamp
14 |
--------------------------------------------------------------------------------
/gamification/core/tests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 |
28 | """
29 | This file demonstrates writing tests using the unittest module. These will pass
30 | when you run "manage.py test".
31 |
32 | Replace this with more appropriate tests for your application.
33 | """
34 |
35 | from django.test import TestCase
36 |
37 |
38 | class SimpleTest(TestCase):
39 | def test_basic_addition(self):
40 | """
41 | Tests that 1 + 1 always equals 2.
42 | """
43 | self.assertEqual(1 + 1, 2)
44 |
--------------------------------------------------------------------------------
/gamification/core/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | from django.conf.urls import patterns, url, include
27 | from views import *
28 |
29 |
30 | urlpatterns = patterns('',
31 |
32 | # PROJECTS
33 |
34 | url(r'^projects/(?P\w+)/award/?$', 'gamification.core.views.award', name='award'),
35 | url(r'^projects/(?P\w+)/points/?$', user_project_points_list),
36 | url(r'^projects/(?P\w+)/points/?format=(?P\w+)?$', user_project_points_list),
37 | url(r'^projects/(?P\w+)/total/?$', user_points),
38 | url(r'^projects/(?P[\w,]+)/badges/?$', user_project_badges_list),
39 | url(r'^projects/(?P[\w,]+)/badges/?format=(?P\w+)?$', user_project_badges_list),
40 |
41 | # POINTS
42 | url(r'^points/?$', user_points_list),
43 |
44 | )
45 |
--------------------------------------------------------------------------------
/gamification/core/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django.db import models
4 | from django.contrib.auth.models import User
5 |
6 | from models import Points, Project, ProjectBadge
7 | from gamification.badges.models import ProjectBadgeToUser
8 |
9 | def badge_count(user):
10 | """
11 | Given a user or queryset of users, this returns the badge
12 | count at each badge level that the user(s) have earned.
13 |
14 | Example:
15 |
16 | >>> badge_count(User.objects.filter(username='admin'))
17 | [{'count': 0, 'badge__level': '1'}, {'count': 0, 'badge__level': '2'}, {'count': 0, 'badge__level': '3'}, {'count': 0, 'badge__level': '4'}]
18 |
19 | Uses a single database query.
20 | """
21 |
22 | projects = Project.objects.all().values('id','name','description')
23 | projects = list(projects)
24 |
25 | projectbadges = ProjectBadge.objects.all()
26 | points = Points.objects.filter(user=user)
27 |
28 | for project in projects:
29 | badges = projectbadges.filter(project_id=project['id']).values('id','name')
30 | badges = list(badges)
31 |
32 | for badge in badges:
33 | badge_points = points.filter(projectbadge_id=badge['id'])
34 | total = badge_points.aggregate(models.Sum('value'))
35 | badge_points = badge_points.values('value','date_awarded','description')
36 | badge_points = list(badge_points)
37 | badge['awarded'] = badge_points
38 | badge['total'] = total['value__sum']
39 |
40 | project['badges'] = badges
41 |
42 | return projects
43 |
44 |
45 | def top_n_points_winners(projects, n):
46 | """
47 | Given a particular project, this returns the top n points
48 | winners at each badge level.
49 |
50 | Example:
51 |
52 | >>> top_five_badge_winners(Project.objects.filter(projectname='geoq'))
53 | [{'count': 0, 'badge__level': '1'}, {'count': 0, 'badge__level': '2'}, {'count': 0, 'badge__level': '3'}, {'count': 0, 'badge__level': '4'}]
54 |
55 | """
56 | points = Points.objects.all()
57 | projects = projects.values('id','active','description','private')
58 | projects = list(projects)
59 |
60 | for project in projects:
61 | projectbadges = ProjectBadge.objects.filter(project_id=project['id']).values('id','description')
62 | projectbadges = list(projectbadges)
63 |
64 | for badge in projectbadges:
65 | badge_points_winners = points.filter(projectbadge_id=badge['id']).select_related('user__username').values('user_id','user__username').annotate(points_count=models.Sum('value')).order_by('-points_count')[:n]
66 | badge['winners'] = badge_points_winners
67 |
68 | project['badges'] = projectbadges
69 |
70 | return projects
71 |
72 | def project_badge_awards(project):
73 | """
74 | Given a particular project, this returns all badge winners.
75 | """
76 | ids = ProjectBadge.objects.filter(project=project).values('id')
77 |
78 | user_badges = ProjectBadgeToUser.objects.filter(projectbadge__in=ids)\
79 | .values('user__username', 'projectbadge__name', 'created', 'projectbadge__badge__icon', 'projectbadge__awardLevel', 'projectbadge__tags')
80 |
81 | project_teams = project[0].teams.all()
82 |
83 | from collections import defaultdict
84 | groups = defaultdict(list)
85 | scores = defaultdict(int)
86 | teams = defaultdict(str)
87 | for obj in user_badges:
88 | username = obj['user__username']
89 | groups[username].append({
90 | 'badge':str(obj['projectbadge__name']),
91 | 'date':str(obj['created']),
92 | 'icon':str(obj['projectbadge__badge__icon']),
93 | 'tags':str(obj['projectbadge__tags']),
94 | 'points':str(obj['projectbadge__awardLevel'])})
95 |
96 | #Find any teams the user is on that are on this project
97 | user_team = ''
98 | for project_team in project_teams:
99 | if username in [(u.username) for u in project_team.members.all()]:
100 | user_team = str(project_team.name)
101 | teams[username] = user_team
102 |
103 | scores[username] += obj['projectbadge__awardLevel']
104 |
105 | #add scores
106 | items = groups.items()
107 | for i in range(len(items)):
108 | items[i] = items[i] + (scores[items[i][0]],) + (teams[items[i][0]],)
109 |
110 | return sorted(items, key=lambda rec: rec[2],reverse=True)
111 |
112 | def get_files_in_dir(mypath):
113 | from os import listdir
114 | from os.path import isfile, join
115 | return [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
116 |
117 |
118 | def top_n_badge_winners(project, num=3):
119 | """
120 | Given a particular project, this returns the top n badge
121 | winners at each badge level.
122 |
123 | Example:
124 |
125 | >>> top_n_badge_winners(Project.objects.filter(name='geoq'),5)
126 | """
127 | projectbadges = ProjectBadge.objects.filter(project=project)
128 | ids = projectbadges.values('id')
129 | badges = projectbadges.values('id','name','description','badge__icon','awardLevel')
130 |
131 | pbtu = ProjectBadgeToUser.objects.filter(projectbadge__in=ids)
132 | badges = list(badges)
133 |
134 | for badge in badges:
135 | badge['leaders'] = top_n_badge_project_winners(pbtu,badge['id'],num)
136 | del badge['id']
137 |
138 | return badges
139 |
140 | def top_n_project_badge_winners(project,badge,num):
141 | """
142 | Given a particular project and badge, determine top n leaders
143 | """
144 |
145 | pbtu = ProjectBadgeToUser.objects.filter(projectbadge=badge)
146 | badge.leaders = top_n_badge_project_winners(pbtu, badge.id, num)
147 |
148 | return badge
149 |
150 | def top_n_badge_project_winners(pbtu_qs,pb_id,num):
151 | topn = pbtu_qs.filter(projectbadge__id=pb_id).values('user__username').annotate(awarded=models.Count('user__username')).order_by('-awarded')[:num]
152 | return list(topn)
153 |
154 | def users_project_points(user,project):
155 | """
156 | Find out a user's total points won on project, factoring in weighted values of badges
157 | """
158 | total = ProjectBadge.objects.filter(user=user,project=project).aggregate(models.Sum('awardLevel'))
159 | return total['awardLevel__sum']
160 |
161 | def users_total_points(user):
162 | """
163 | Find out a user's points from all projects
164 | """
165 | total = ProjectBadge.objects.filter(user=user).aggregate(models.Sum('awardLevel'))
166 | return total['awardLevel__sum']
167 |
168 | def user_project_badge_count(user,project):
169 | """
170 | Given a user or queryset of users, this returns the badge
171 | count at each badge level that the user(s) have earned.
172 |
173 | Example:
174 |
175 | >>> badge_count(User.objects.filter(username='admin'))
176 | [{'count': 0, 'badge__level': '1'}, {'count': 0, 'badge__level': '2'}, {'count': 0, 'badge__level': '3'}, {'count': 0, 'badge__level': '4'}]
177 |
178 | Uses a single database query.
179 | """
180 |
181 | projectbadges = ProjectBadge.objects.filter(project_id=project.id).values('id','name','description')
182 | projectbadgeids = projectbadges.values('id')
183 | points = Points.objects.filter(user=user,projectbadge__id__in=projectbadgeids)
184 | badges = list(projectbadges)
185 |
186 | for badge in badges:
187 | badge_points = points.filter(projectbadge_id=badge['id'])
188 | total = badge_points.aggregate(models.Sum('value'))
189 | badge_points = badge_points.values('value','date_awarded','description')
190 | badge_points = list(badge_points)
191 | badge['awarded'] = badge_points
192 | badge['total'] = total['value__sum']
193 |
194 | return badges
--------------------------------------------------------------------------------
/gamification/events/__init__.py:
--------------------------------------------------------------------------------
1 | # Permission is hereby granted, free of charge, to any person obtaining
2 | # a copy of this software and associated documentation files (the
3 | # "Software"), to deal in the Software without restriction, including
4 | # without limitation the rights to use, copy, modify, merge, publish,
5 | # distribute, sublicense, and/or sell copies of the Software, and to
6 | # permit persons to whom the Software is furnished to do so, as long as
7 | # any reuse or further development of the software attributes the
8 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
9 | # 'This software (django-gamification)
10 | # is provided to the public as a courtesy of the National
11 | # Geospatial-Intelligence Agency.
12 | #
13 | # The above copyright notice and this permission notice shall be
14 | # included in all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/gamification/events/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | from models import Event, Policy
27 | from django.contrib import admin
28 |
29 | class EventAdmin(admin.ModelAdmin):
30 | list_display = ('id', 'user', 'project', 'event_dtg', 'details')
31 |
32 | class PolicyAdmin(admin.ModelAdmin):
33 | list_display = ('id', 'project','projectbadge', 'type')
34 |
35 |
36 | admin.site.register(Event, EventAdmin)
37 | admin.site.register(Policy, PolicyAdmin)
--------------------------------------------------------------------------------
/gamification/events/experimental/mandatory_training_1.policy:
--------------------------------------------------------------------------------
1 | from state import DemoState
2 |
3 | rule "Rule 1":
4 | when:
5 | $state := DemoState((project.name == 'training') and ('course_complete' in event_data) and ('008031' in event_data['course_complete']) and ('008189' in event_data['course_complete']) and ('008582' in event_data['course_complete']) and ('009446' in event_data['course_complete']) and ('013413' in event_data['course_complete']) and ('013567' in event_data['course_complete']) and ('016003' in event_data['course_complete']) and ('016094' in event_data['course_complete']) and ('017724' in event_data['course_complete']) and ('020146' in event_data['course_complete']) and ('023416' in event_data['course_complete']))
6 | then:
7 | $state.award($state.user, $state.project, 'Gold')
8 |
--------------------------------------------------------------------------------
/gamification/events/experimental/mandatory_training_2.policy:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from state import DemoState
3 |
4 | rule "Rule 1":
5 | when:
6 | $state := DemoState((project.name == 'training') and ('course_complete' in event_data) and ('008031' in event_data['course_complete']) and (event_data['course_complete']['008031'] < datetime(2015, 1, 1)) and ('008189' in event_data['course_complete']) and (event_data['course_complete']['008189'] < datetime(2015, 1, 1)) and ('008582' in event_data['course_complete']) and (event_data['course_complete']['008582'] < datetime(2015, 1, 1)) and ('009446' in event_data['course_complete']) and (event_data['course_complete']['009446'] < datetime(2015, 1, 1)) and ('013413' in event_data['course_complete']) and (event_data['course_complete']['013413'] < datetime(2015, 1, 1)) and ('013567' in event_data['course_complete']) and (event_data['course_complete']['013567'] < datetime(2015, 1, 1)) and ('016003' in event_data['course_complete']) and (event_data['course_complete']['016003'] < datetime(2015, 1, 1)) and ('016094' in event_data['course_complete']) and (event_data['course_complete']['016094'] < datetime(2015, 1, 1)) and ('017724' in event_data['course_complete']) and (event_data['course_complete']['017724'] < datetime(2015, 1, 1)) and ('020146' in event_data['course_complete']) and (event_data['course_complete']['020146'] < datetime(2015, 1, 1)) and ('023416' in event_data['course_complete']) and (event_data['course_complete']['023416'] < datetime(2015, 1, 1)))
7 | then:
8 | $state.award($state.user, $state.project, 'Gold')
9 | halt
10 |
11 | rule "Rule 2":
12 | when:
13 | $state := DemoState((project.name == 'training') and ('course_complete' in event_data) and ('008031' in event_data['course_complete']) and (event_data['course_complete']['008031'] <= datetime(2015, 1, 1)) and ('008189' in event_data['course_complete']) and (event_data['course_complete']['008189'] <= datetime(2015, 1, 1)) and ('008582' in event_data['course_complete']) and (event_data['course_complete']['008582'] <= datetime(2015, 1, 1)) and ('009446' in event_data['course_complete']) and (event_data['course_complete']['009446'] <= datetime(2015, 1, 1)) and ('013413' in event_data['course_complete']) and (event_data['course_complete']['013413'] <= datetime(2015, 1, 1)) and ('013567' in event_data['course_complete']) and (event_data['course_complete']['013567'] <= datetime(2015, 1, 1)) and ('016003' in event_data['course_complete']) and (event_data['course_complete']['016003'] <= datetime(2015, 1, 1)) and ('016094' in event_data['course_complete']) and (event_data['course_complete']['016094'] <= datetime(2015, 1, 1)) and ('017724' in event_data['course_complete']) and (event_data['course_complete']['017724'] <= datetime(2015, 1, 1)) and ('020146' in event_data['course_complete']) and (event_data['course_complete']['020146'] <= datetime(2015, 1, 1)) and ('023416' in event_data['course_complete']) and (event_data['course_complete']['023416'] <= datetime(2015, 1, 1)))
14 | then:
15 | $state.award($state.user, $state.project, 'Silver')
16 | halt
17 |
18 | rule "Rule 3":
19 | when:
20 | $state := DemoState((project.name == 'training') and ('course_complete' in event_data) and ('008031' in event_data['course_complete']) and (event_data['course_complete']['008031'] >= datetime(2015, 1, 1)) and ('008189' in event_data['course_complete']) and (event_data['course_complete']['008189'] >= datetime(2015, 1, 1)) and ('008582' in event_data['course_complete']) and (event_data['course_complete']['008582'] >= datetime(2015, 1, 1)) and ('009446' in event_data['course_complete']) and (event_data['course_complete']['009446'] >= datetime(2015, 1, 1)) and ('013413' in event_data['course_complete']) and (event_data['course_complete']['013413'] >= datetime(2015, 1, 1)) and ('013567' in event_data['course_complete']) and (event_data['course_complete']['013567'] >= datetime(2015, 1, 1)) and ('016003' in event_data['course_complete']) and (event_data['course_complete']['016003'] >= datetime(2015, 1, 1)) and ('016094' in event_data['course_complete']) and (event_data['course_complete']['016094'] >= datetime(2015, 1, 1)) and ('017724' in event_data['course_complete']) and (event_data['course_complete']['017724'] >= datetime(2015, 1, 1)) and ('020146' in event_data['course_complete']) and (event_data['course_complete']['020146'] >= datetime(2015, 1, 1)) and ('023416' in event_data['course_complete']) and (event_data['course_complete']['023416'] >= datetime(2015, 1, 1)))
21 | then:
22 | $state.award($state.user, $state.project, 'Bronze')
23 |
--------------------------------------------------------------------------------
/gamification/events/experimental/rules_engine.py:
--------------------------------------------------------------------------------
1 | # Permission is hereby granted, free of charge, to any person obtaining
2 | # a copy of this software and associated documentation files (the
3 | # "Software"), to deal in the Software without restriction, including
4 | # without limitation the rights to use, copy, modify, merge, publish,
5 | # distribute, sublicense, and/or sell copies of the Software, and to
6 | # permit persons to whom the Software is furnished to do so, as long as
7 | # any reuse or further development of the software attributes the
8 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
9 | # 'This software (django-gamification)
10 | # is provided to the public as a courtesy of the National
11 | # Geospatial-Intelligence Agency.
12 | #
13 | # The above copyright notice and this permission notice shall be
14 | # included in all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | from datetime import datetime
25 | from intellect.Intellect import Intellect
26 | from state import DemoState
27 |
28 | # Experimental class that was used for early rules engine testing purposes
29 | class RulesEngine(object):
30 |
31 | def reason(self, policy, state):
32 | intellect = Intellect()
33 | intellect.learn(policy)
34 | intellect.learn(state)
35 | intellect.reason()
36 |
37 | def run_test(self, policy, event_dtg):
38 | username = 'John Doe'
39 | projectname = 'training'
40 | event_type = 'course_complete'
41 | event_data = {}
42 | event_data[event_type] = training_event_data = {}
43 |
44 | course_ids = ['008031', '008189', '008582', '009446', '013413', '013567', '016003', '016094', '017724', '020146', '023416']
45 |
46 | for cid in course_ids:
47 | print ('Adding course {0}'.format(cid))
48 | training_event_data[cid] = event_dtg
49 |
50 | class Object(object):
51 | pass
52 | user = Object()
53 | user.username = username
54 | project = Object()
55 | project.name = projectname
56 |
57 | self.reason(policy, DemoState(user, project, event_data))
58 |
59 | if __name__ == '__main__':
60 | policy1 = "from state import DemoState\nrule 'Rule 1':\n\twhen:\n\t\t$state := DemoState((project.name == 'training') and ('course_complete' in event_data) and ('008031' in event_data['course_complete']) and ('008189' in event_data['course_complete']) and ('008582' in event_data['course_complete']) and ('009446' in event_data['course_complete']) and ('013413' in event_data['course_complete']) and ('013567' in event_data['course_complete']) and ('016003' in event_data['course_complete']) and ('016094' in event_data['course_complete']) and ('017724' in event_data['course_complete']) and ('020146' in event_data['course_complete']) and ('023416' in event_data['course_complete']))\n\tthen:\n\t\t$state.award($state.user, $state.project, 'Gold')\n"
61 | utilIntellect = Intellect()
62 | policy2 = utilIntellect.local_file_uri('./mandatory_training_2.policy')
63 | engine = RulesEngine()
64 | engine.run_test(policy1, '') # User should get gold
65 | engine.run_test(policy2, datetime.now()) # User should get gold
66 | engine.run_test(policy2, datetime(2015, 1, 1)) # User should get silver
67 | engine.run_test(policy2, datetime(2015, 2, 1)) # User should get bronze
68 |
--------------------------------------------------------------------------------
/gamification/events/experimental/state.py:
--------------------------------------------------------------------------------
1 | # Permission is hereby granted, free of charge, to any person obtaining
2 | # a copy of this software and associated documentation files (the
3 | # "Software"), to deal in the Software without restriction, including
4 | # without limitation the rights to use, copy, modify, merge, publish,
5 | # distribute, sublicense, and/or sell copies of the Software, and to
6 | # permit persons to whom the Software is furnished to do so, as long as
7 | # any reuse or further development of the software attributes the
8 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
9 | # 'This software (django-gamification)
10 | # is provided to the public as a courtesy of the National
11 | # Geospatial-Intelligence Agency.
12 | #
13 | # The above copyright notice and this permission notice shall be
14 | # included in all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | class DemoState(object):
25 |
26 | def __init__(self, user, project, event_data):
27 | self._user = user
28 | self._project = project
29 | self._event_data = event_data # A dictionary of dictionaries
30 |
31 | @property
32 | def user(self):
33 | return self._user
34 |
35 | @property
36 | def project(self):
37 | return self._project
38 |
39 | @property
40 | def event_data(self):
41 | return self._event_data
42 |
43 | @event_data.setter
44 | def event_data(self, event_data):
45 | self._event_data = event_data
46 |
47 | def award(self, user, project, award_id):
48 | print('User "{0}" got award "{1}" for project "{2}"').format(user.username, award_id, project.name)
49 |
--------------------------------------------------------------------------------
/gamification/events/fixtures/camp_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pk": 11,
4 | "model": "events.policy",
5 | "fields": {
6 | "project": 5,
7 | "type": 0,
8 | "projectbadge": 23,
9 | "rule": "from gamification.events.models import Event\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('attendance' == details_map['event_type']) and (dtg.date() >= datetime.date(2014,7,21)) and (dtg.date() <= datetime.date(2014,7,25)))\n\tthen:\n\t\t$event.update_state('attendance', $event.event_dtg.date(), \"\")\n"
10 | }
11 | },
12 | {
13 | "pk": 12,
14 | "model": "events.policy",
15 | "fields": {
16 | "project": 5,
17 | "type": 1,
18 | "projectbadge": 23,
19 | "rule": "from gamification.events.state import State\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('attendance' in event_data) and (datetime.date(2014,7,21) in event_data['attendance']) and (datetime.date(2014,7,22) in event_data['attendance']) and (datetime.date(2014,7,23) in event_data['attendance']) and (datetime.date(2014,7,24) in event_data['attendance']) and (datetime.date(2014,7,25) in event_data['attendance']))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
20 | }
21 | },
22 | {
23 | "pk": 13,
24 | "model": "events.policy",
25 | "fields": {
26 | "project": 5,
27 | "type": 0,
28 | "projectbadge": 24,
29 | "rule": "from gamification.events.models import Event\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('attendance' == details_map['event_type']) and (dtg.date() >= datetime.date(2014,7,29)) and (dtg.date() <= datetime.date(2014,8,1)))\n\tthen:\n\t\t$event.update_state('attendance', $event.event_dtg.date(), \"\")\n"
30 | }
31 | },
32 | {
33 | "pk": 14,
34 | "model": "events.policy",
35 | "fields": {
36 | "project": 5,
37 | "type": 1,
38 | "projectbadge": 24,
39 | "rule": "from gamification.events.state import State\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('attendance' in event_data) and (datetime.date(2014,7,28) in event_data['attendance']) and (datetime.date(2014,7,29) in event_data['attendance']) and (datetime.date(2014,7,30) in event_data['attendance']) and (datetime.date(2014,7,31) in event_data['attendance']) and (datetime.date(2014,8,1) in event_data['attendance']))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
40 | }
41 | },
42 | {
43 | "pk": 15,
44 | "model": "events.policy",
45 | "fields": {
46 | "project": 5,
47 | "type": 0,
48 | "projectbadge": 22,
49 | "rule": "from gamification.events.models import Event\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('attendance' == details_map['event_type']) and (dtg.date() >= datetime.date(2014,7,14)) and (dtg.date() <= datetime.date(2014,7,18)))\n\tthen:\n\t\t$event.update_state('attendance', $event.event_dtg.date(), \"\")\n"
50 | }
51 | },
52 | {
53 | "pk": 16,
54 | "model": "events.policy",
55 | "fields": {
56 | "project": 5,
57 | "type": 1,
58 | "projectbadge": 22,
59 | "rule": "from gamification.events.state import State\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('attendance' in event_data) and (datetime.date(2014,7,14) in event_data['attendance']) and (datetime.date(2014,7,15) in event_data['attendance']) and (datetime.date(2014,7,16) in event_data['attendance']) and (datetime.date(2014,7,17) in event_data['attendance']) and (datetime.date(2014,7,18) in event_data['attendance']))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
60 | }
61 | },
62 | {
63 | "pk": 17,
64 | "model": "events.policy",
65 | "fields": {
66 | "project": 5,
67 | "type": 0,
68 | "projectbadge": 14,
69 | "rule": "from gamification.events.models import Event\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('attendance' == details_map['event_type']) and (is_today()) and (dtg.date() >= datetime.date(2014,7,14)) and (dtg.date() <= datetime.date(2014,8,1)))\n\tthen:\n\t\t$event.update_state('participation', $event.event_dtg.date(), \"\")\n"
70 | }
71 | },
72 | {
73 | "pk": 18,
74 | "model": "events.policy",
75 | "fields": {
76 | "project": 5,
77 | "type": 1,
78 | "projectbadge": 14,
79 | "rule": "from gamification.events.state import State\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('participation' in event_data) and (len(event_data['participation']) == 1))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
80 | }
81 | },
82 | {
83 | "pk": 18,
84 | "model": "events.policy",
85 | "fields": {
86 | "project": 5,
87 | "type": 0,
88 | "projectbadge": 13,
89 | "rule": "from gamification.events.models import Event\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('awardee' in details_map) and ('nga' == details_map['event_type']) and (is_today()) and (dtg.date() >= datetime.date(2014,7,14)) and (dtg.date() <= datetime.date(2014,8,1)))\n\tthen:\n\t\t$event.update_state('nga', $event.user, details_map['awardee'])\n"
90 | }
91 | },
92 | {
93 | "pk": 19,
94 | "model": "events.policy",
95 | "fields": {
96 | "project": 5,
97 | "type": 1,
98 | "projectbadge": 13,
99 | "rule": "from gamification.events.state import State\nimport datetime\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('nga' in event_data) and (len(event_data['nga']) == 1))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
100 | }
101 | }
102 | ]
103 |
--------------------------------------------------------------------------------
/gamification/events/fixtures/initial_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "pk": 1,
4 | "model": "events.policy",
5 | "fields": {
6 | "project": 3,
7 | "type": 0,
8 | "projectbadge": 6,
9 | "rule": "from gamification.events.models import Event\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('aoi_complete' == details_map['event_type']) and ('aoi_id' in details_map) and (is_current_event) and (details_map['feature_count'] > 0))\n\tthen:\n\t\t$event.update_state('aoi_complete', $event.details_map['aoi_id'], $event.event_dtg)\n"
10 | }
11 | },
12 | {
13 | "pk": 2,
14 | "model": "events.policy",
15 | "fields": {
16 | "project": 3,
17 | "type": 1,
18 | "projectbadge": 6,
19 | "rule": "from gamification.events.state import State\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('aoi_complete' in event_data) and (len(event_data['aoi_complete']) > 0))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
20 | }
21 | },
22 | {
23 | "pk": 3,
24 | "model": "events.policy",
25 | "fields": {
26 | "project": 3,
27 | "type": 0,
28 | "projectbadge": 5,
29 | "rule": "from gamification.events.models import Event\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and ('aoi_complete' in details_map['event_type']) and ('aoi_id' in details_map) and (details_map['feature_count'] > 0))\n\tthen:\n\t\t$event.update_state('aoi_complete', $event.details_map['aoi_id'], $event.event_dtg)\n"
30 | }
31 | },
32 | {
33 | "pk": 4,
34 | "model": "events.policy",
35 | "fields": {
36 | "project": 3,
37 | "type": 1,
38 | "projectbadge": 5,
39 | "rule": "from gamification.events.state import State\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('aoi_complete' in event_data) and (len(event_data['aoi_complete']) % 3 == 0))\n\tthen:\n\t\t$state.award($state.user, $state.project)\n"
40 | }
41 | },
42 | {
43 | "pk": 9,
44 | "model": "events.policy",
45 | "fields": {
46 | "project": 4,
47 | "type": 0,
48 | "projectbadge": 7,
49 | "rule": "from gamification.events.models import Event\nrule 'Rule 1':\n\twhen:\n\t\t$event := Event(('event_type' in details_map) and (is_current_event))\n\tthen:\n\t\t$event.update_state('action_complete',$event.details_map['event_type'],$event.event_dtg)\n"
50 | }
51 | },
52 | {
53 | "pk": 10,
54 | "model": "events.policy",
55 | "fields": {
56 | "project": 4,
57 | "type": 1,
58 | "projectbadge": 7,
59 | "rule": "from gamification.events.state import State\nrule 'Rule 1':\n\twhen:\n\t\t$state := State(('action_complete' in event_data))\n\tthen:\n\t\t$state.award($state.user,$state.project)\n"
60 | }
61 | }
62 | ]
63 |
--------------------------------------------------------------------------------
/gamification/events/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import datetime
3 | from south.db import db
4 | from south.v2 import SchemaMigration
5 | from django.db import models
6 |
7 |
8 | class Migration(SchemaMigration):
9 |
10 | def forwards(self, orm):
11 | # Adding model 'Event'
12 | db.create_table(u'events_event', (
13 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14 | ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
15 | ('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Project'])),
16 | ('event_dtg', self.gf('django.db.models.fields.DateTimeField')()),
17 | ('details', self.gf('django.db.models.fields.TextField')()),
18 | ))
19 | db.send_create_signal(u'events', ['Event'])
20 |
21 | # Adding model 'Policy'
22 | db.create_table(u'events_policy', (
23 | (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
24 | ('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['core.Project'])),
25 | ('projectbadge', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['badges.ProjectBadge'])),
26 | ('type', self.gf('django.db.models.fields.IntegerField')()),
27 | ('rule', self.gf('django.db.models.fields.TextField')()),
28 | ))
29 | db.send_create_signal(u'events', ['Policy'])
30 |
31 |
32 | def backwards(self, orm):
33 | # Deleting model 'Event'
34 | db.delete_table(u'events_event')
35 |
36 | # Deleting model 'Policy'
37 | db.delete_table(u'events_policy')
38 |
39 |
40 | models = {
41 | u'auth.group': {
42 | 'Meta': {'object_name': 'Group'},
43 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
44 | 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
45 | 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
46 | },
47 | u'auth.permission': {
48 | 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
49 | 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
50 | 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
51 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
52 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
53 | },
54 | u'auth.user': {
55 | 'Meta': {'object_name': 'User'},
56 | 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
57 | 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
58 | 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
59 | 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
60 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
61 | 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
62 | 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
63 | 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
64 | 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
65 | 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
66 | 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
67 | 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
68 | 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
69 | },
70 | u'badges.badge': {
71 | 'Meta': {'object_name': 'Badge'},
72 | 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
73 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
74 | 'level': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
75 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
76 | },
77 | u'badges.projectbadge': {
78 | 'Meta': {'object_name': 'ProjectBadge'},
79 | 'awardLevel': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
80 | 'badge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.Badge']"}),
81 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
82 | 'description': ('django.db.models.fields.TextField', [], {}),
83 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
84 | 'multipleAwards': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
85 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
86 | 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Project']"}),
87 | 'user': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': u"orm['badges.ProjectBadgeToUser']", 'to': u"orm['auth.User']"})
88 | },
89 | u'badges.projectbadgetouser': {
90 | 'Meta': {'object_name': 'ProjectBadgeToUser'},
91 | 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
92 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
93 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
94 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
95 | },
96 | u'contenttypes.contenttype': {
97 | 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
98 | 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
99 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
100 | 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
101 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
102 | },
103 | u'core.project': {
104 | 'Meta': {'ordering': "('-created_at',)", 'object_name': 'Project'},
105 | 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
106 | 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
107 | 'description': ('django.db.models.fields.TextField', [], {}),
108 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
109 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
110 | 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
111 | 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
112 | },
113 | u'events.event': {
114 | 'Meta': {'object_name': 'Event'},
115 | 'details': ('django.db.models.fields.TextField', [], {}),
116 | 'event_dtg': ('django.db.models.fields.DateTimeField', [], {}),
117 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
118 | 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Project']"}),
119 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
120 | },
121 | u'events.policy': {
122 | 'Meta': {'object_name': 'Policy'},
123 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
124 | 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['core.Project']"}),
125 | 'projectbadge': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['badges.ProjectBadge']"}),
126 | 'rule': ('django.db.models.fields.TextField', [], {}),
127 | 'type': ('django.db.models.fields.IntegerField', [], {})
128 | }
129 | }
130 |
131 | complete_apps = ['events']
--------------------------------------------------------------------------------
/gamification/events/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/events/migrations/__init__.py
--------------------------------------------------------------------------------
/gamification/events/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | import json
27 | import datetime
28 | from django.contrib.auth.models import User
29 | from gamification.core.models import Project, ProjectBadge
30 | from django.db import models
31 |
32 | class Event(models.Model):
33 | """
34 | An Event is an action reported by an external system
35 | """
36 |
37 | user = models.ForeignKey(User)
38 | project = models.ForeignKey(Project)
39 | event_dtg = models.DateTimeField('event date')
40 | details = models.TextField(editable=False)
41 |
42 | def __init__(self, *args, **kw):
43 | # dictionary for the details of the event
44 | self.details_map = {}
45 | super(Event, self).__init__(*args, **kw)
46 | if self.details:
47 | try:
48 | self.details_map = json.loads(self.details)
49 | except TypeError:
50 | self.details_map = self.details
51 |
52 | def save(self, *args, **kw):
53 | self.details = json.dumps(self.details_map)
54 | super(Event, self).save(*args, **kw)
55 |
56 | @property
57 | def dtg(self):
58 | return self.event_dtg
59 |
60 | @property
61 | def details_map(self):
62 | return self._details_map
63 |
64 | @details_map.setter
65 | def details_map(self, details_map):
66 | self._details_map = details_map
67 |
68 | @property
69 | def state(self):
70 | return self._state
71 |
72 | @state.setter
73 | def state(self, state):
74 | self._state = state
75 |
76 | @property
77 | def is_current_event(self):
78 | return self._current_event
79 |
80 | @property
81 | def is_today(self):
82 | return datetime.datetime.date() == event_dtg.date()
83 |
84 | @state.setter
85 | def current_event(self, current_event_id):
86 | self._current_event = (self.id == current_event_id)
87 |
88 | # Adds specified event data to the state
89 | def update_state(self, outer_key, inner_key, inner_value):
90 | try:
91 | if not outer_key in self._state.event_data:
92 | self._state._event_data[outer_key] = {}
93 | self._state._event_data[outer_key][inner_key] = inner_value
94 | except AttributeError:
95 | print 'AttributeError'
96 | pass
97 |
98 | class Policy(models.Model):
99 | """
100 | A Policy is a condition - action specifier for the rules engine. Will include 1 or more Rules
101 | """
102 |
103 | STATE_POLICY = 0
104 | AWARD_POLICY = 1
105 | POLICY_CHOICES = ( (STATE_POLICY, 'State Policy'), (AWARD_POLICY, 'Award Policy'), )
106 |
107 | project = models.ForeignKey(Project)
108 | projectbadge = models.ForeignKey(ProjectBadge)
109 | type = models.IntegerField(choices=POLICY_CHOICES)
110 | rule = models.TextField()
111 |
112 | def __unicode__(self):
113 | try:
114 | kind = self.POLICY_CHOICES[self.projectbadge.type][1]
115 | except:
116 | kind = 'Policy'
117 | return u"%s for %s on %s" % (kind, self.projectbadge.name, self.project.name)
118 |
119 |
120 | #class Rule(models.Model):
121 | # """
122 | # A Rule is a decision specifier that will be the basis for a Policy
123 | # """
124 | #
125 | # name = models.CharField(max_length=100)
126 | # policy = models.ForeignKey(Policy)
127 | # badge = models.ForeignKey(ProjectBadge)
128 | # conditions = models.TextField(editable=False)
129 | #
130 | # def __init__(self, *args, **kw):
131 | # # dictionary for the details of the event
132 | # self.conditions_list = []
133 | # super(Event, self).__init__(*args, **kw)
134 | # if self.conditions:
135 | # self.conditions_list = json.loads(self.conditions)
136 | #
137 | # def save(self, *args, **kw):
138 | # self.conditions = json.dumps(self.conditions_list)
139 | # super(Event, self).save(*args, **kw)
--------------------------------------------------------------------------------
/gamification/events/state.py:
--------------------------------------------------------------------------------
1 | # Permission is hereby granted, free of charge, to any person obtaining
2 | # a copy of this software and associated documentation files (the
3 | # "Software"), to deal in the Software without restriction, including
4 | # without limitation the rights to use, copy, modify, merge, publish,
5 | # distribute, sublicense, and/or sell copies of the Software, and to
6 | # permit persons to whom the Software is furnished to do so, as long as
7 | # any reuse or further development of the software attributes the
8 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
9 | # 'This software (django-gamification)
10 | # is provided to the public as a courtesy of the National
11 | # Geospatial-Intelligence Agency.
12 | #
13 | # The above copyright notice and this permission notice shall be
14 | # included in all copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | from django.core.exceptions import ObjectDoesNotExist
25 | from gamification.badges.models import ProjectBadge, ProjectBadgeToUser
26 |
27 | class State(object):
28 | """
29 | A State is a collection of event data (associated with a user and project)
30 | that will be submitted to the rules engine for reasoning.
31 | """
32 |
33 | def __init__(self, user, project, projectbadge, event_data):
34 | self._user = user
35 | self._project = project
36 | self._projectbadge = projectbadge
37 | self._event_data = event_data # A dictionary of dictionaries
38 |
39 | @property
40 | def user(self):
41 | return self._user
42 |
43 | @property
44 | def project(self):
45 | return self._project
46 |
47 | @property
48 | def event_data(self):
49 | return self._event_data
50 |
51 | @event_data.setter
52 | def event_data(self, event_data):
53 | self._event_data = event_data
54 |
55 | # Awards a project badge to a user (if the user does not yet have the badge)
56 | def award(self, user, project):
57 | project_badge = self._projectbadge
58 | project_badge.award_to(user)
--------------------------------------------------------------------------------
/gamification/png.py:
--------------------------------------------------------------------------------
1 | # http://www.codeproject.com/KB/web-image/pnggammastrip.aspx
2 |
3 | import struct
4 | import sys
5 | import urllib
6 | import urllib2
7 | import zlib
8 |
9 | def read_signature(stream):
10 | return stream.read(8)
11 |
12 | class Chunk:
13 | def __init__(self, size, chunk_type, data, crc):
14 | self.size =size
15 | self.chunk_type = chunk_type
16 | self.data = data
17 | self.crc = crc
18 |
19 | def __repr__(self):
20 | return repr(self.chunk_type) + ' ' + repr(self.size)
21 |
22 | def write(self, stream):
23 | stream.write(struct.pack('!I', self.size))
24 | stream.write(self.chunk_type)
25 | stream.write(self.data)
26 | stream.write(self.crc)
27 |
28 | @staticmethod
29 | def read(stream):
30 | len_string = stream.read(4)
31 | if not len_string:
32 | return None
33 |
34 | length = struct.unpack('!I', len_string)[0]
35 | chunk_type = stream.read(4)
36 | data = stream.read(length)
37 | crc = stream.read(4)
38 | return Chunk(length, chunk_type, data, crc)
39 |
40 | @staticmethod
41 | def create(chunk_type, data):
42 | data_length = len(data)
43 | payload = chunk_type + data
44 | chunk_crc = zlib.crc32(payload) & 0xFFFFFFFF
45 | return Chunk(data_length, chunk_type, data, struct.pack('!I', chunk_crc))
46 |
47 | class iTXtChunk(Chunk):
48 | def __init__(self, chunk):
49 | Chunk.__init__(self, chunk.size, chunk.chunk_type, chunk.data, chunk.crc)
50 | keyword_length = self.data.find('\0')
51 | self.keyword = self.data[:keyword_length]
52 | self.text = unicode(self.data[keyword_length+5:], 'utf-8')
53 |
54 | @staticmethod
55 | def create(keyword, text):
56 | '''Create an uncompressed, untranslated iTXt chunk
57 | '''
58 | null = '\0'
59 | uncompressed = '\0\0'
60 |
61 | chunk_data = keyword
62 | chunk_data += null
63 | chunk_data += uncompressed
64 | # no language specified
65 | chunk_data += null
66 | # no translated keyword
67 | chunk_data += null
68 | chunk_data += unicode(text).encode('utf-8')
69 |
70 | return Chunk.create('iTXt', chunk_data)
71 |
72 | def all_chunks(stream):
73 | while True:
74 | chunk = Chunk.read(stream)
75 |
76 | if chunk:
77 | yield chunk
78 | else:
79 | return
80 |
81 | def add_itXT_to_png(text, in_stream, out_stream):
82 | signature = png.read_signature(in_stream)
83 | out_stream.write(signature)
84 |
85 | for chunk in png.all_chunks(in_stream):
86 | if chunk.chunk_type == 'IEND':
87 | break;
88 | chunk.write(out_stream)
89 |
90 | itxt_chunk = png.iTXtChunk.create('openbadges',text)
91 | itxt_chunk.write(out_stream)
92 |
93 | # write IEND
94 | chunk.write(out_stream)
95 |
96 |
97 |
98 | if __name__ == '__main__':
99 | inputFilename = sys.argv[1]
100 | inputFile = file(inputFilename, 'rb')
101 | read_signature(inputFile)
102 |
103 | for chunk in all_chunks(inputFile):
104 | print chunk
--------------------------------------------------------------------------------
/gamification/receivers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 | from django.dispatch import receiver
28 |
29 | from account.signals import password_changed
30 | from account.signals import user_sign_up_attempt, user_signed_up
31 | from account.signals import user_login_attempt, user_logged_in
32 |
33 | from eventlog.models import log
34 |
35 |
36 | @receiver(user_logged_in)
37 | def handle_user_logged_in(sender, **kwargs):
38 | log(
39 | user=kwargs.get("user"),
40 | action="USER_LOGGED_IN",
41 | extra={}
42 | )
43 |
44 |
45 | @receiver(password_changed)
46 | def handle_password_changed(sender, **kwargs):
47 | log(
48 | user=kwargs.get("user"),
49 | action="PASSWORD_CHANGED",
50 | extra={}
51 | )
52 |
53 |
54 | @receiver(user_login_attempt)
55 | def handle_user_login_attempt(sender, **kwargs):
56 | log(
57 | user=None,
58 | action="LOGIN_ATTEMPTED",
59 | extra={
60 | "username": kwargs.get("username"),
61 | "result": kwargs.get("result")
62 | }
63 | )
64 |
65 |
66 | @receiver(user_sign_up_attempt)
67 | def handle_user_sign_up_attempt(sender, **kwargs):
68 | log(
69 | user=None,
70 | action="SIGNUP_ATTEMPTED",
71 | extra={
72 | "username": kwargs.get("username"),
73 | "email": kwargs.get("email"),
74 | "result": kwargs.get("result")
75 | }
76 | )
77 |
78 |
79 | @receiver(user_signed_up)
80 | def handle_user_signed_up(sender, **kwargs):
81 | log(
82 | user=kwargs.get("user"),
83 | action="USER_SIGNED_UP",
84 | extra={}
85 | )
86 |
--------------------------------------------------------------------------------
/gamification/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==1.5.4
2 | Django-Select2==4.2.1
3 | PIL==1.1.7
4 | Paver==1.2.1
5 | South==0.8.2
6 | django-appconf==0.6
7 | #django-badges==0.1.6
8 | django-bootstrap-toolkit==2.15.0
9 | django-compressor==1.3
10 | django-reversion==1.7.1
11 | django-singleton==0.1.7
12 | django-stronghold==0.2.2
13 | jsonfield==0.9.17
14 | psycopg2==2.5.1
15 | requests==1.2.3
16 | six==1.4.1
17 | wsgiref==0.1.2
18 |
--------------------------------------------------------------------------------
/gamification/site_media/media/badge_images/bronze.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/site_media/media/badge_images/bronze.png
--------------------------------------------------------------------------------
/gamification/site_media/media/badge_images/gold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/site_media/media/badge_images/gold.png
--------------------------------------------------------------------------------
/gamification/site_media/media/badge_images/silver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/site_media/media/badge_images/silver.png
--------------------------------------------------------------------------------
/gamification/startup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 | import copy
28 |
29 | from django.conf import settings
30 | from django.utils.importlib import import_module
31 | from django.utils.module_loading import module_has_submodule
32 |
33 |
34 | def autoload(submodules):
35 | for app in settings.INSTALLED_APPS:
36 | mod = import_module(app)
37 | for submodule in submodules:
38 | try:
39 | import_module("{0}.{1}".format(app, submodule))
40 | except:
41 | if module_has_submodule(mod, submodule):
42 | raise
43 |
44 |
45 | def run():
46 | autoload(["receivers"])
47 |
--------------------------------------------------------------------------------
/gamification/static/README:
--------------------------------------------------------------------------------
1 | This directory is used to store static assets for your project. User media files
2 | (FileFields/ImageFields) are not stored here.
3 |
4 | The convention for this directory is:
5 |
6 | * css/ — stores CSS files
7 | * js/ — stores Javascript files
8 | * img/ — stores image files
9 |
--------------------------------------------------------------------------------
/gamification/static/css/project_list.css:
--------------------------------------------------------------------------------
1 | div.row {
2 | margin-left: 0px;
3 | }
4 | .badge-row.leader {
5 | padding: 0px; line-height: 1em;
6 | }
7 | .badge-row.leader img{
8 | padding: 0px;width: 24px;vertical-align: baseline;
9 | }
10 |
11 | .badge-row {
12 | padding:5px; border:1px solid gray
13 | }
14 | .badge-row h4 {
15 | margin: 0px 0px 5px 0px;
16 | }
17 | .badge-row:nth-child(even) {
18 | background-color: lightcyan;
19 | }
20 | .badge-row:nth-child(odd) {
21 | background-color: lightyellow;
22 | }
23 | .badge-row span.dtg {
24 | display: inline; padding: 0px;
25 | }
26 | .badge-row span.awardee {
27 | display: inline; padding: 0px; width: 150px;
28 | }
29 | .badge-row span {
30 | display: inline-block; vertical-align: top; padding:10px;
31 | }
32 | #header_title h1{
33 | margin:0px;
34 | }
35 | #header_title {
36 | margin-bottom: 20px;
37 | }
38 | .tab-content{
39 | max-height: 650px;
40 | overflow: scroll;
41 | }
--------------------------------------------------------------------------------
/gamification/static/img/bronze.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/img/bronze.png
--------------------------------------------------------------------------------
/gamification/static/img/gold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/img/gold.png
--------------------------------------------------------------------------------
/gamification/static/img/silver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/img/silver.png
--------------------------------------------------------------------------------
/gamification/static/img/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/img/title.png
--------------------------------------------------------------------------------
/gamification/static/js/TimeCircles/TimeCircles.css:
--------------------------------------------------------------------------------
1 | /**
2 | * This element is created inside your target element
3 | * It is used so that your own element will not need to be altered
4 | **/
5 | .time_circles {
6 | position: relative;
7 | width: 100%;
8 | height: 100%;
9 | }
10 |
11 | /**
12 | * This is all the elements used to house all text used
13 | * in time circles
14 | **/
15 | .time_circles > div {
16 | position: absolute;
17 | text-align: center;
18 | }
19 |
20 | /**
21 | * Titles (Days, Hours, etc)
22 | **/
23 | .time_circles > div > h4 {
24 | margin: 0px;
25 | padding: 0px;
26 | text-align: center;
27 | text-transform: uppercase;
28 | font-family: 'Century Gothic', Arial;
29 | }
30 |
31 | /**
32 | * Time numbers, ie: 12
33 | **/
34 | .time_circles > div > span {
35 | display: block;
36 | width: 100%;
37 | text-align: center;
38 | font-family: 'Century Gothic', Arial;
39 | font-size: 300%;
40 | margin-top: 0.4em;
41 | font-weight: bold;
42 | }
43 |
--------------------------------------------------------------------------------
/gamification/static/js/maths.js:
--------------------------------------------------------------------------------
1 | //Jay's math helpers
2 | _.mixin({ deepClone: function (p_object) { return JSON.parse(JSON.stringify(p_object)); } });
3 |
4 | var maths = {};
5 | maths.heightOnSin=function(theta_min,theta_max,step,steps,amplitude,func){
6 | func = func || Math.sin; //Find the Sin value by default, you can also pass in Math.cos
7 |
8 | var percent = step/steps;
9 | var theta = theta_min + ((theta_max-theta_min)*percent);
10 | return Math.sin(theta * Math.PI) * amplitude;
11 | };
12 | maths.sizeFromAmountRange=function(size_min,size_max,amount,amount_min,amount_max){
13 | var percent = (amount-amount_min)/(amount_max-amount_min);
14 | return size_min+ (percent * (size_max-size_min));
15 | };
16 | maths.colorBlendFromAmountRange=function(color_start,color_end,amount,amount_min,amount_max){
17 | var percent = (amount-amount_min)/(amount_max-amount_min);
18 |
19 | if (color_start.substring(0,1) =="#") color_start = color_start.substring(1,7);
20 | if (color_end.substring(0,1) =="#") color_end = color_end.substring(1,7);
21 |
22 | var s_r = color_start.substring(0,2);
23 | var s_g = color_start.substring(2,4);
24 | var s_b = color_start.substring(4,6);
25 | var e_r = color_end.substring(0,2);
26 | var e_g = color_end.substring(2,4);
27 | var e_b = color_end.substring(4,6);
28 |
29 | var n_r = Math.abs(parseInt((parseInt(s_r, 16) * percent) + (parseInt(e_r, 16) * (1-percent))));
30 | var n_g = Math.abs(parseInt((parseInt(s_g, 16) * percent) + (parseInt(e_g, 16) * (1-percent))));
31 | var n_b = Math.abs(parseInt((parseInt(s_b, 16) * percent) + (parseInt(e_b, 16) * (1-percent))));
32 | var rgb = maths.decimalToHex(n_r) + maths.decimalToHex(n_g) + maths.decimalToHex(n_b);
33 |
34 | return "#"+rgb;
35 | };
36 | maths.decimalToHex = function(d, padding) {
37 | var hex = Number(d).toString(16);
38 | padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
39 |
40 | while (hex.length < padding) {
41 | hex = "0" + hex;
42 | }
43 |
44 | return hex;
45 | };
46 | maths.idealTextColor=function(bgColor) {
47 |
48 | var nThreshold = 150;
49 | var components = maths.getRGBComponents(bgColor);
50 | var bgDelta = (components.R * 0.299) + (components.G * 0.587) + (components.B * 0.114);
51 |
52 | return ((255 - bgDelta) < nThreshold) ? "#000000" : "#ffffff";
53 | };
54 | maths.getRGBComponents=function(color) {
55 |
56 | var r = color.substring(1, 3);
57 | var g = color.substring(3, 5);
58 | var b = color.substring(5, 7);
59 |
60 | return {
61 | R: parseInt(r, 16),
62 | G: parseInt(g, 16),
63 | B: parseInt(b, 16)
64 | };
65 | };
--------------------------------------------------------------------------------
/gamification/static/js/underscore.string.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"use strict";var n=t.prototype.trim,r=t.prototype.trimRight,i=t.prototype.trimLeft,s=function(e){return e*1||0},o=function(e,t){if(t<1)return"";var n="";while(t>0)t&1&&(n+=e),t>>=1,e+=e;return n},u=[].slice,a=function(e){return e==null?"\\s":e.source?e.source:"["+p.escapeRegExp(e)+"]"},f={lt:"<",gt:">",quot:'"',apos:"'",amp:"&"},l={};for(var c in f)l[f[c]]=c;var h=function(){function e(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}var n=o,r=function(){return r.cache.hasOwnProperty(arguments[0])||(r.cache[arguments[0]]=r.parse(arguments[0])),r.format.call(null,r.cache[arguments[0]],arguments)};return r.format=function(r,i){var s=1,o=r.length,u="",a,f=[],l,c,p,d,v,m;for(l=0;l=0?"+"+a:a,v=p[4]?p[4]=="0"?"0":p[4].charAt(1):" ",m=p[6]-t(a).length,d=p[6]?n(v,m):"",f.push(p[5]?a+d:d+a)}}return f.join("")},r.cache={},r.parse=function(e){var t=e,n=[],r=[],i=0;while(t){if((n=/^[^\x25]+/.exec(t))!==null)r.push(n[0]);else if((n=/^\x25{2}/.exec(t))!==null)r.push("%");else{if((n=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(t))===null)throw new Error("[_.sprintf] huh?");if(n[2]){i|=1;var s=[],o=n[2],u=[];if((u=/^([a-z_][a-z_\d]*)/i.exec(o))===null)throw new Error("[_.sprintf] huh?");s.push(u[1]);while((o=o.substring(u[0].length))!=="")if((u=/^\.([a-z_][a-z_\d]*)/i.exec(o))!==null)s.push(u[1]);else{if((u=/^\[(\d+)\]/.exec(o))===null)throw new Error("[_.sprintf] huh?");s.push(u[1])}n[2]=s}else i|=2;if(i===3)throw new Error("[_.sprintf] mixing positional and named placeholders is not (yet) supported");r.push(n)}t=t.substring(n[0].length)}return r},r}(),p={VERSION:"2.3.0",isBlank:function(e){return e==null&&(e=""),/^\s*$/.test(e)},stripTags:function(e){return e==null?"":t(e).replace(/<\/?[^>]+>/g,"")},capitalize:function(e){return e=e==null?"":t(e),e.charAt(0).toUpperCase()+e.slice(1)},chop:function(e,n){return e==null?[]:(e=t(e),n=~~n,n>0?e.match(new RegExp(".{1,"+n+"}","g")):[e])},clean:function(e){return p.strip(e).replace(/\s+/g," ")},count:function(e,n){return e==null||n==null?0:t(e).split(n).length-1},chars:function(e){return e==null?[]:t(e).split("")},swapCase:function(e){return e==null?"":t(e).replace(/\S/g,function(e){return e===e.toUpperCase()?e.toLowerCase():e.toUpperCase()})},escapeHTML:function(e){return e==null?"":t(e).replace(/[&<>"']/g,function(e){return"&"+l[e]+";"})},unescapeHTML:function(e){return e==null?"":t(e).replace(/\&([^;]+);/g,function(e,n){var r;return n in f?f[n]:(r=n.match(/^#x([\da-fA-F]+)$/))?t.fromCharCode(parseInt(r[1],16)):(r=n.match(/^#(\d+)$/))?t.fromCharCode(~~r[1]):e})},escapeRegExp:function(e){return e==null?"":t(e).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")},splice:function(e,t,n,r){var i=p.chars(e);return i.splice(~~t,~~n,r),i.join("")},insert:function(e,t,n){return p.splice(e,t,0,n)},include:function(e,n){return n===""?!0:e==null?!1:t(e).indexOf(n)!==-1},join:function(){var e=u.call(arguments),t=e.shift();return t==null&&(t=""),e.join(t)},lines:function(e){return e==null?[]:t(e).split("\n")},reverse:function(e){return p.chars(e).reverse().join("")},startsWith:function(e,n){return n===""?!0:e==null||n==null?!1:(e=t(e),n=t(n),e.length>=n.length&&e.slice(0,n.length)===n)},endsWith:function(e,n){return n===""?!0:e==null||n==null?!1:(e=t(e),n=t(n),e.length>=n.length&&e.slice(e.length-n.length)===n)},succ:function(e){return e==null?"":(e=t(e),e.slice(0,-1)+t.fromCharCode(e.charCodeAt(e.length-1)+1))},titleize:function(e){return e==null?"":t(e).replace(/(?:^|\s)\S/g,function(e){return e.toUpperCase()})},camelize:function(e){return p.trim(e).replace(/[-_\s]+(.)?/g,function(e,t){return t.toUpperCase()})},underscored:function(e){return p.trim(e).replace(/([a-z\d])([A-Z]+)/g,"$1_$2").replace(/[-\s]+/g,"_").toLowerCase()},dasherize:function(e){return p.trim(e).replace(/([A-Z])/g,"-$1").replace(/[-_\s]+/g,"-").toLowerCase()},classify:function(e){return p.titleize(t(e).replace(/_/g," ")).replace(/\s/g,"")},humanize:function(e){return p.capitalize(p.underscored(e).replace(/_id$/,"").replace(/_/g," "))},trim:function(e,r){return e==null?"":!r&&n?n.call(e):(r=a(r),t(e).replace(new RegExp("^"+r+"+|"+r+"+$","g"),""))},ltrim:function(e,n){return e==null?"":!n&&i?i.call(e):(n=a(n),t(e).replace(new RegExp("^"+n+"+"),""))},rtrim:function(e,n){return e==null?"":!n&&r?r.call(e):(n=a(n),t(e).replace(new RegExp(n+"+$"),""))},truncate:function(e,n,r){return e==null?"":(e=t(e),r=r||"...",n=~~n,e.length>n?e.slice(0,n)+r:e)},prune:function(e,n,r){if(e==null)return"";e=t(e),n=~~n,r=r!=null?t(r):"...";if(e.length<=n)return e;var i=function(e){return e.toUpperCase()!==e.toLowerCase()?"A":" "},s=e.slice(0,n+1).replace(/.(?=\W*\w*$)/g,i);return s.slice(s.length-2).match(/\w\w/)?s=s.replace(/\s*\S+$/,""):s=p.rtrim(s.slice(0,s.length-1)),(s+r).length>e.length?e:e.slice(0,s.length)+r},words:function(e,t){return p.isBlank(e)?[]:p.trim(e,t).split(t||/\s+/)},pad:function(e,n,r,i){e=e==null?"":t(e),n=~~n;var s=0;r?r.length>1&&(r=r.charAt(0)):r=" ";switch(i){case"right":return s=n-e.length,e+o(r,s);case"both":return s=n-e.length,o(r,Math.ceil(s/2))+e+o(r,Math.floor(s/2));default:return s=n-e.length,o(r,s)+e}},lpad:function(e,t,n){return p.pad(e,t,n)},rpad:function(e,t,n){return p.pad(e,t,n,"right")},lrpad:function(e,t,n){return p.pad(e,t,n,"both")},sprintf:h,vsprintf:function(e,t){return t.unshift(e),h.apply(null,t)},toNumber:function(e,n){if(e==null||e=="")return 0;e=t(e);var r=s(s(e).toFixed(~~n));return r===0&&!e.match(/^0+$/)?Number.NaN:r},numberFormat:function(e,t,n,r){if(isNaN(e)||e==null)return"";e=e.toFixed(~~t),r=r||",";var i=e.split("."),s=i[0],o=i[1]?(n||".")+i[1]:"";return s.replace(/(\d)(?=(?:\d{3})+$)/g,"$1"+r)+o},strRight:function(e,n){if(e==null)return"";e=t(e),n=n!=null?t(n):n;var r=n?e.indexOf(n):-1;return~r?e.slice(r+n.length,e.length):e},strRightBack:function(e,n){if(e==null)return"";e=t(e),n=n!=null?t(n):n;var r=n?e.lastIndexOf(n):-1;return~r?e.slice(r+n.length,e.length):e},strLeft:function(e,n){if(e==null)return"";e=t(e),n=n!=null?t(n):n;var r=n?e.indexOf(n):-1;return~r?e.slice(0,r):e},strLeftBack:function(e,t){if(e==null)return"";e+="",t=t!=null?""+t:t;var n=e.lastIndexOf(t);return~n?e.slice(0,n):e},toSentence:function(e,t,n,r){t=t||", ",n=n||" and ";var i=e.slice(),s=i.pop();return e.length>2&&r&&(n=p.rtrim(t)+n),i.length?i.join(t)+n+s:s},toSentenceSerial:function(){var e=u.call(arguments);return e[3]=!0,p.toSentence.apply(p,e)},slugify:function(e){if(e==null)return"";var n="ąàáäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",r="aaaaaaaaceeeeeiiiilnoooooouuuunczz",i=new RegExp(a(n),"g");return e=t(e).toLowerCase().replace(i,function(e){var t=n.indexOf(e);return r.charAt(t)||"-"}),p.dasherize(e.replace(/[^\w\s-]/g,""))},surround:function(e,t){return[t,e,t].join("")},quote:function(e){return p.surround(e,'"')},exports:function(){var e={};for(var t in this){if(!this.hasOwnProperty(t)||t.match(/^(?:include|contains|reverse)$/))continue;e[t]=this[t]}return e},repeat:function(e,n,r){if(e==null)return"";n=~~n;if(r==null)return o(t(e),n);for(var i=[];n>0;i[--n]=e);return i.join(r)},levenshtein:function(e,n){if(e==null&&n==null)return 0;if(e==null)return t(n).length;if(n==null)return t(e).length;e=t(e),n=t(n);var r=[],i,s;for(var o=0;o<=n.length;o++)for(var u=0;u<=e.length;u++)o&&u?e.charAt(u-1)===n.charAt(o-1)?s=i:s=Math.min(r[u],r[u-1],i)+1:s=o+u,i=r[u],r[u]=s;return r.pop()}};p.strip=p.trim,p.lstrip=p.ltrim,p.rstrip=p.rtrim,p.center=p.lrpad,p.rjust=p.lpad,p.ljust=p.rpad,p.contains=p.include,p.q=p.quote,typeof exports!="undefined"?(typeof module!="undefined"&&module.exports&&(module.exports=p),exports._s=p):typeof define=="function"&&define.amd?define("underscore.string",[],function(){return p}):(e._=e._||{},e._.string=e._.str=p)}(this,String);
--------------------------------------------------------------------------------
/gamification/static/themes/camping/badges.css:
--------------------------------------------------------------------------------
1 | .personJersey {
2 | display:inline-block;
3 | margin:4px;
4 | vertical-align: top;
5 |
6 | width: 210px;
7 | height: 250px;
8 | position: relative;
9 | }
10 |
11 | .personHeaderCard {
12 | display:inline-block;
13 | margin:2px;
14 | vertical-align: top;
15 |
16 | width: 200px;
17 | background-repeat: no-repeat;
18 | position: relative;
19 | }
20 |
21 | .cardHeight100 {
22 | background: url(card_wood_100.png);
23 | background-size: 200px 100px;
24 | height: 100px;
25 | }
26 |
27 | .cardHeight150 {
28 | background: url(card_wood_150.png);
29 | background-size: 200px 150px;
30 | height: 150px;
31 | }
32 |
33 | .cardHeight200 {
34 | background: url(card_wood_200.png);
35 | background-size: 200px 200px;
36 | height: 200px;
37 | }
38 | .cardHeight300 {
39 | background: url(card_wood_300.png);
40 | background-size: 300px 300px;
41 | height: 300px;
42 | }
43 | .personHeaderCardText {
44 | font-family:Arial;
45 | cursor: cell;
46 | padding: 2px;
47 | font-size:17px;
48 | color:white;
49 | font-weight:bold;
50 | text-shadow: 2px 2px #000000;
51 | text-align:center;
52 | top:17px;
53 | left:0;
54 | right:0;
55 | margin-left:auto;
56 | margin-right:auto;
57 | /*left:50px;*/
58 | position: absolute;
59 | }
60 | .personHeaderTextLeft {
61 | left: 10px;
62 | right: 155px;
63 | color: yellow;
64 | }
65 | .personHeaderTextRight {
66 | left: 155px;
67 | right: 10px;
68 | color: rgb(230, 254, 253);
69 | }
70 |
71 | .personCardBadgeHolder {
72 | position: absolute;
73 | top:52px;
74 | left:18px;
75 | }
76 | .personBadgeHolderCard {
77 | display:inline-block;
78 | background-repeat: no-repeat;
79 | padding:4px;
80 | margin:3px;
81 | /*margin-bottom: 0px;*/
82 | margin-top: 1px;
83 | position:relative;
84 | /*border:1px solid black;*/
85 | }
86 |
87 | .personHeader {
88 | border:2px solid black;
89 | display:inline-block;
90 | margin:2px;
91 | background-color: #eff;
92 | border-image: url(corner_border_cyber_blue.png) 12% 8% 8% 8% round;
93 | border-width: 14px;
94 | vertical-align: top;
95 | max-width: 470px;
96 | max-height: 74px;
97 | overflow-y: scroll;
98 | }
99 | .personHeaderText {
100 | font-family:Arial;
101 | padding: 2px;
102 | font-size:16px;
103 | color:black;
104 | font-weight:bold;
105 | text-align:center
106 | }
107 |
108 | .personBadgeHolder {
109 | display:inline-block;
110 | background-repeat: no-repeat;
111 | padding:4px;
112 | margin:4px;
113 | position:relative;
114 | /*border:1px solid black;*/
115 | }
116 |
117 | .personBadgeHolderMeatball {
118 | color:white;
119 | opacity:0.85;
120 | font-weight:bold;
121 | text-align:center;
122 | position:absolute;
123 | background-color: #ffedc1;
124 | border:1px solid orange;
125 | }
126 | .personBadgeHolderText {
127 | font-family:Arial;
128 | font-weight:bold;
129 | text-align:center;
130 | color:black;
131 | position:absolute;
132 | }
--------------------------------------------------------------------------------
/gamification/static/themes/camping/blue_jersey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/blue_jersey.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/canoe_green_sideways.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/canoe_green_sideways.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/card_wood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/card_wood.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/card_wood_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/card_wood_100.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/card_wood_150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/card_wood_150.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/card_wood_200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/card_wood_200.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/card_wood_300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/card_wood_300.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/corner_border_brown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/corner_border_brown.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/corner_border_cyber_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/corner_border_cyber_blue.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/oar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stephenrjones/django-gamification/d22882f148375102ec351cb2bc75275083468d73/gamification/static/themes/camping/oar.png
--------------------------------------------------------------------------------
/gamification/static/themes/camping/paddles.js:
--------------------------------------------------------------------------------
1 | var paddles = {canvas:null, $canvas:null, ctx:null, loadedImages:0, loadedArray:[]};
2 | paddles.imageArray = "canoe_green_sideways.png oar.png".split(" ");
3 | paddles.imageUrlPrefix = "/static/themes/camping/";
4 |
5 | paddles.init = function(){
6 | //Initialization
7 |
8 | paddles.$canvas = $('')
9 | .attr({width:1000,height:220,id:'badge_data_canvas'})
10 | .text("This graph doesn't show on your browser")
11 | .prependTo($('#leader_board'));
12 |
13 | paddles.canvas = document.getElementById('badge_data_canvas');
14 | if (paddles.canvas && paddles.canvas.getContext){
15 | paddles.ctx = paddles.canvas.getContext('2d');
16 | paddles.preloadImages();
17 | } else {
18 | console.log("No Canvas Support");
19 | if (paddles.$canvas) paddles.$canvas.hide();
20 | }
21 | };
22 |
23 | paddles.preloadImages = function() {
24 | for (var i = 0; i < paddles.imageArray.length; i++) {
25 | paddles.loadedArray[i] = new Image();
26 | paddles.loadedArray[i].addEventListener("load", paddles.trackProgress, true);
27 | var url = paddles.imageArray[i];
28 | if (document.location.host != "") url = paddles.imageUrlPrefix + url;
29 | paddles.loadedArray[i].src = url;
30 | }
31 | };
32 |
33 | paddles.trackProgress = function() {
34 | paddles.loadedImages++;
35 | if (paddles.loadedImages == paddles.imageArray.length) {
36 | paddles.imagesLoaded();
37 | }
38 | };
39 |
40 | paddles.imagesLoaded = function() {
41 | //Run after all images are ready
42 | //TODO: Pass a list of visualization types and call appropriately with proper data
43 | paddles.draw_canoe_and_oars(project_info.badge_json || []);
44 | };
45 |
46 | paddles.draw_canoe_and_oars = function(badge_info){
47 | //Shortcuts
48 | var ctx = paddles.ctx;
49 | var canoe = paddles.loadedArray[0];
50 | var oar = paddles.loadedArray[1];
51 |
52 | var canvas_width = paddles.canvas.width;
53 | var canvas_height = paddles.canvas.height;
54 |
55 | //Variables
56 | var canvas_spacing = 50;
57 | var canoe_spacing = 15;
58 | var canoe_spacing_right = 25;
59 | var canoe_width = canvas_width-(canvas_spacing*2);
60 | var canoe_height = 200 / (1460/canoe_width);
61 | var oar_width = 70;
62 | var num_oars = 20;
63 | if (badge_info && badge_info.length < num_oars) num_oars = badge_info.length;
64 | if (num_oars < 2) num_oars = 2;
65 |
66 | var oar_spacing = parseInt((canoe_width-canvas_spacing-canoe_spacing_right-(canoe_spacing/2)) / (num_oars-1));
67 | ctx.font="bold 12px Verdana";
68 |
69 | var badges_max=0;
70 | var badges_min=100000000;
71 | var points_max=0;
72 | var points_min=100000000;
73 |
74 | for (var i=0;ibadges_max) badges_max=awards;
79 | if (awardspoints_max) points_max=points;
81 | if (points
6 |
31 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/gamification/templates/_footer.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
3 | {% trans "© 2013 <your company here>" %}
4 |
--------------------------------------------------------------------------------
/gamification/templates/homepage.html:
--------------------------------------------------------------------------------
1 | {% extends "banner_base.html" %}
2 |
3 | {% load i18n %}
4 | {% load url from future %}
5 |
6 | {% block head_title %}{% trans "Welcome" %}{% endblock %}
7 |
8 | {% block body_class %}home{% endblock %}
9 |
10 | {% block banner %}
11 | {% trans "Welcome to Pinax" %}
12 |
13 | {% blocktrans %}
14 | Pinax is a Django
15 | project intended to provide a starting point for websites. By
16 | integrating numerous reusable Django apps to take care of the
17 | things that many sites have in common, it lets you focus on what
18 | makes your site different.
19 | {% endblocktrans %}
20 |
21 |
22 | About Account Project
23 |
24 | {% blocktrans %}
25 | In addition to what is provided by the "zero" project, this project
26 | provides thorough integration with django-user-accounts, adding
27 | comprehensive account management functionality. It is a foundation
28 | suitable for most sites that have user accounts.
29 | {% endblocktrans %}
30 |
31 |
32 | {% if user.is_authenticated %}
33 | {% url "what_next" as what_next_url %}
34 | {% blocktrans %}Wondering What Next ?{% endblocktrans %}
35 | {% else %}
36 | {% url "account_login" as login_url %}
37 | {% url "account_signup" as signup_url %}
38 | {% blocktrans %}You can Log In or Sign Up to try out the site.{% endblocktrans %}
39 | {% endif %}
40 | {% endblock %}
41 |
--------------------------------------------------------------------------------
/gamification/templates/site_base.html:
--------------------------------------------------------------------------------
1 | {% extends "theme_base.html" %}
2 |
3 | {% load metron_tags %}
4 | {% load i18n %}
5 |
6 | {% block extra_head_base %}
7 | {% block extra_head %}{% endblock %}
8 | {% endblock %}
9 |
10 | {% block footer %}
11 | {% include "_footer.html" %}
12 | {% endblock %}
13 |
14 | {% block extra_body_base %}
15 | {% analytics %}
16 | {% block extra_body %}{% endblock %}
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/gamification/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 | from django.conf import settings
28 | from django.conf.urls import patterns, include, url
29 | from django.conf.urls.static import static
30 | from django.views.generic import TemplateView, ListView
31 |
32 | from django.contrib import admin
33 | admin.autodiscover()
34 | from gamification.core.models import Project
35 | from gamification.core.views import *
36 | from gamification.events.views import handle_event, assign_badge
37 |
38 | urlpatterns = patterns("",
39 | url(r"^gamification/$", TemplateView.as_view(template_name="core/index.html"), name="home"),
40 | url(r"^admin/", include(admin.site.urls)),
41 | url(r"^account/", include("account.urls")),
42 | url(r"^users/?$", UserView.as_view(template_name='core/users.html'), name='user_list'),
43 | url(r"^users/(?P[\w .-@]+)/", include("gamification.core.urls")),
44 | url(r"^projects/$", master_project_list),
45 |
46 | url(r"^projects/all/", MasterProjectListView.as_view(template_name='core/masterprojects_list.html'), name='master-project-list'),
47 | url(r"^projects/(?P[\w ]+)/?$", ProjectListView.as_view(template_name='core/projects_list.html'), name='project-list'),
48 | url(r"^projects/(?P[\w ]+)/admin/?$", ProjectAdminListView.as_view(template_name='core/project_admin.html'), name='project-admin'),
49 |
50 | url(r"^projects/(?P[\w ]+)/(?P\w+)/?$", ProjectListView.as_view(template_name='core/projects_list.html'), name='project-list'),
51 |
52 | url(r"^projects/(?P[\w ]+)/leaders/?$", project_all_badgeleaders_view),
53 | # url(r"^projects/(?P\w+)/badges/?$", BadgeListView.as_view(template_name='core/badge_list.html'), name='badge-list'),
54 | url(r"^projects/(?P[\w ]+)/badges/(?P\w+)/leaders/?$", project_badgeleaders_view),
55 | url(r'^badges/?$', MasterBadgeListView.as_view(template_name='core/master_badge_list.html'), name='master-badge-list'),
56 | url(r'^users/(?P[\w .-@]+)/projects/(?P[\w ]+)/event/?$', handle_event),
57 | url(r'^users/(?P[\w .-@]+)/assign_badge/(?P[\w ]+)?$', assign_badge),
58 | url(r'^users/(?P[\w .-@]+)/create/?$', create_new_user),
59 | url(r'^$', MasterBadgeListView.as_view(template_name="core/index.html"), name="home"),
60 | url(r'^users/(?P[\w .-@])/projects/(?P\w+)/event/?$', handle_event),
61 | url(r'^users/(?P[\w .-@])/assign_badge/(?P\w+)?$', assign_badge),
62 | url(r'^users/(?P[\w .-@])/create/?$', create_new_user),
63 | url(r'^$', TemplateView.as_view(template_name="core/index.html"), name="home"),
64 |
65 | # Open Badges interoperability. Define an Issuer
66 | url(r'^projects/(?P\w+)/badges/(?P\w+)/issuer/?$', \
67 | get_issuer, name="openbadges_issuer"),
68 |
69 | # and a way to retrieve a badge's image
70 | url(r'^projects/(?P\w+)/badges/(?P\w+)/image/?$', \
71 | get_image, name="openbadges_image"),
72 |
73 | # a badge's metadata
74 | url(r'^projects/(?P\w+)/badges/(?P\w+)/metadata/?$', \
75 | get_metadata, name="openbadges_metadata"),
76 |
77 | # a badge's criteria
78 | url(r'projects/(?P\w+)/badges/(?P\w+)/criteria/?$', \
79 | get_criteria, name='openbadges_criteria'),
80 |
81 | # badge instance metadata
82 | url(r'projects/(?P\w+)/badges/(?P\w+)/users/(?P[\w .-@])/award/?$', \
83 | get_badge_award, name='openbadges_award'),
84 | )
85 |
86 | # urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
87 |
--------------------------------------------------------------------------------
/gamification/wsgi.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | ## Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 | """
28 | WSGI config for django_gamification project.
29 |
30 | This module contains the WSGI application used by Django's development server
31 | and any production WSGI deployments. It should expose a module-level variable
32 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
33 | this application via the ``WSGI_APPLICATION`` setting.
34 |
35 | Usually you will have the standard Django WSGI application here, but it also
36 | might make sense to replace the whole Django WSGI application with a custom one
37 | that later delegates to the Django one. For example, you could introduce WSGI
38 | middleware here, or combine a Django application with an application of another
39 | framework.
40 |
41 | """
42 | import os
43 |
44 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gamification.settings")
45 |
46 | import gamification.startup as startup
47 | startup.run()
48 |
49 | # This application object is used by any WSGI server configured to use this
50 | # file. This includes Django's development server, if the WSGI_APPLICATION
51 | # setting points here.
52 | from django.core.wsgi import get_wsgi_application
53 | application = get_wsgi_application()
54 |
55 | # Apply WSGI middleware here.
56 | # from helloworld.wsgi import HelloWorldApplication
57 | # application = HelloWorldApplication(application)
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 |
27 | import os, sys
28 |
29 | if __name__ == "__main__":
30 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gamification.settings")
31 | os.environ['PGCONNECT_TIMEOUT'] = '30'
32 |
33 | manage_dir = os.path.dirname(os.path.realpath(__file__))
34 | sys.path.append(os.path.join(manage_dir, 'gamification'))
35 |
36 | from django.core.management import execute_from_command_line
37 | import gamification.startup as startup
38 | startup.run()
39 | execute_from_command_line(sys.argv)
40 |
--------------------------------------------------------------------------------
/pavement.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining
4 | # a copy of this software and associated documentation files (the
5 | # "Software"), to deal in the Software without restriction, including
6 | # without limitation the rights to use, copy, modify, merge, publish,
7 | # distribute, sublicense, and/or sell copies of the Software, and to
8 | # permit persons to whom the Software is furnished to do so, as long as
9 | # any reuse or further development of the software attributes the
10 | # National Geospatial-Intelligence Agency (NGA) authorship as follows:
11 | # 'This software (django-gamification)
12 | # is provided to the public as a courtesy of the National
13 | # Geospatial-Intelligence Agency.
14 | #
15 | # The above copyright notice and this permission notice shall be
16 | # included in all copies or substantial portions of the Software.
17 | #
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
26 | import os
27 | import sys
28 |
29 | from paver.easy import *
30 | from paver.setuputils import setup
31 |
32 | sys.path.append(os.path.dirname(os.path.realpath(__file__)))
33 |
34 | setup(
35 | name="gamification",
36 | packages=['gamification'],
37 | version='0.0.0.1',
38 | url="",
39 | author="Site Admin",
40 | author_email="admin@localhost"
41 | )
42 |
43 |
44 | @task
45 | def install_dependencies():
46 | """ Installs dependencies."""
47 | sh('pip install --upgrade -r gamification/requirements.txt')
48 |
49 |
50 | @cmdopts([
51 | ('fixture=', 'f', 'Fixture to install"'),
52 | ])
53 | @task
54 | def install_fixture(options):
55 | """ Loads the supplied fixture """
56 | fixture = options.get('fixture')
57 | sh("python manage.py loaddata {fixture}".format(fixture=fixture))
58 |
59 |
60 | @task
61 | def install_dev_fixtures():
62 | """ Installs development fixtures in the correct order """
63 | fixtures = [
64 | 'gamification/core/fixtures/initial_data.json', # Core
65 | 'gamification/badges/fixtures/initial_data.json', # Badges
66 | 'gamification/events/fixtures/initial_data.json', # Events
67 | ]
68 |
69 | for fixture in fixtures:
70 | sh("python manage.py loaddata {fixture}".format(fixture=fixture))
71 |
72 | @task
73 | def sync_initial():
74 | sh("python manage.py syncdb; python manage.py migrate --all 2> /dev/null")
75 | sh("python manage.py syncdb; python manage.py migrate --all 2> /dev/null")
76 | sh("python manage.py syncdb; python manage.py migrate core")
77 | sh("python manage.py syncdb; python manage.py migrate --all")
78 |
79 | @task
80 | def sync():
81 | """ Runs the syncdb process with migrations """
82 | sh("python manage.py migrate core")
83 | sh("python manage.py syncdb --noinput")
84 | sh("python manage.py migrate --all")
85 |
86 |
87 | @cmdopts([
88 | ('bind=', 'b', 'Bind server to provided IP address and port number.'),
89 | ])
90 | @task
91 | def start_django(options):
92 | """ Starts the Django application. """
93 | bind = options.get('bind', '')
94 | sh('python manage.py runserver %s &' % bind)
95 |
96 |
97 | @needs(['sync',
98 | 'start_django'])
99 | def start():
100 | """ Syncs the database and then starts the development server. """
101 | info("Gamification is now available.")
102 |
103 |
104 | @cmdopts([
105 | ('template=', 'T', 'Database template to use when creating new database, defaults to "template_postgis"'),
106 | ])
107 | @task
108 | def createdb(options):
109 | """ Creates the database in postgres. """
110 | from gamification import settings
111 | template = options.get('template', 'template_postgis')
112 | database = settings.DATABASES.get('default').get('NAME')
113 | sh('createdb {database}'.format(database=database, template=template))
114 |
115 |
116 | @task
117 | def create_db_user():
118 | """ Creates the database in postgres. """
119 | from gamification import settings
120 | database = settings.DATABASES.get('default').get('NAME')
121 | user = settings.DATABASES.get('default').get('USER')
122 | password = settings.DATABASES.get('default').get('PASSWORD')
123 |
124 | sh('psql -d {database} -c {sql}'.format(database=database,
125 | sql='"CREATE USER {user} WITH PASSWORD \'{password}\';"'.format(user=user,
126 | password=password)))
127 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | --allow-external antlr-python-runtime
2 | --allow-unverified antlr-python-runtime
3 | --allow-external PIL
4 | --allow-unverified PIL
5 |
6 | Django==1.5.4
7 | Django-Select2==4.2.1
8 | PIL==1.1.7
9 | Paver==1.2.1
10 | South==0.8.2
11 | django-appconf==0.6
12 | django-bootstrap3==4.7.1
13 | django-bootstrap-toolkit==2.15.0
14 | django-compressor==1.3
15 | django-forms-bootstrap==2.0.3.post1
16 | django-geoexplorer==3.0.4
17 | django-jsonfield==0.8.12
18 | django-reversion==1.7.1
19 | django-singleton==0.1.7
20 | django-stronghold==0.2.2
21 | django-tastypie==0.11.0
22 | django-user-accounts==1.0b13
23 | eventlog==0.6.2
24 | #gamification==0.0.0.1
25 | jsonfield==0.9.17
26 | metron==1.1
27 | pinax-theme-bootstrap==3.0a9
28 | psycopg2==2.5.1
29 | python-dateutil==2.2
30 | python-mimeparse==0.1.4
31 | pytz==2012j
32 | requests==1.2.3
33 | six==1.4.1
34 | wsgiref==0.1.2
35 | Intellect==1.4.9
36 | djangorestframework==2.3.14
37 | django-cors-headers==0.12
--------------------------------------------------------------------------------