Commit 1e90decf authored by Laury Bueno's avatar Laury Bueno
Browse files

[Stats] Add a new app to track user activity

parent 6bb0a42e
# Django Courses
A smart Django application to offer MOOC courses functionality.
## Quickstart
Install Django Courses:
```bash
pip install git+https://git.hacklab.com.br/hackmooc/django-courses.git@master#egg=django-courses
```
Add it to your `INSTALLED_APPS`:
```python
INSTALLED_APPS = (
...
'courses.apps.CoursesConfig',
...
)
```
Add Django Courses's URL patterns:
```python
from courses import urls as courses_urls
urlpatterns = [
...
url(r'^', include(courses_urls)),
...
]
```
## Activity streams
Accepted actions:
- user accessed the platform
=============================
Django Courses
=============================
.. image:: https://badge.fury.io/py/django-courses.svg
:target: https://badge.fury.io/py/django-courses
.. image:: https://travis-ci.org/hacklabr/django-courses.svg?branch=master
:target: https://travis-ci.org/hacklabr/django-courses
.. image:: https://codecov.io/gh/hacklabr/django-courses/branch/master/graph/badge.svg
:target: https://codecov.io/gh/hacklabr/django-courses
A smart Django application to offer MOOC courses functionality
Documentation
-------------
The full documentation is at https://django-courses.readthedocs.io.
Quickstart
----------
Install Django Courses::
pip install django-courses
Add it to your `INSTALLED_APPS`:
.. code-block:: python
INSTALLED_APPS = (
...
'courses.apps.CoursesConfig',
...
)
Add Django Courses's URL patterns:
.. code-block:: python
from courses import urls as courses_urls
urlpatterns = [
...
url(r'^', include(courses_urls)),
...
]
Features
--------
* TODO
Running Tests
-------------
Does the code actually work?
::
source <YOURVIRTUALENV>/bin/activate
(myenv) $ pip install tox
(myenv) $ tox
Credits
-------
Tools used in rendering this package:
* Cookiecutter_
* `cookiecutter-djangopackage`_
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`cookiecutter-djangopackage`: https://github.com/pydanny/cookiecutter-djangopackage
# -*- coding: utf-8
from django.apps import AppConfig
from django.contrib.auth import get_user_model
class CoursesConfig(AppConfig):
......
# -*- coding: utf-8
from django.apps import AppConfig
from django.contrib.auth import get_user_model
class CoursesStatsConfig(AppConfig):
name = 'courses.stats'
def ready(self):
from actstream import registry
registry.register(get_user_model())
registry.register('courses.Course')
registry.register('discussion.Topic')
registry.register('discussion.Forum')
# Generated by Django 2.2.15 on 2020-09-09 16:04
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='AccessibleArea',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Name')),
('slug', models.SlugField(max_length=255, unique=True, verbose_name='Slug')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
),
]
from django.db import models
from django.utils.translation import ugettext_lazy as _
class AccessibleArea(models.Model):
name = models.CharField(
_('Name'),
max_length=255,
)
slug = models.SlugField(
_('Slug'),
max_length=255,
unique=True,
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
from rest_framework import serializers
class UserActionsSerializer(serializers.Serializer):
verb = serializers.CharField(required=True, max_length=100)
action_object_id = serializers.IntegerField(required=False)
action_object_type = serializers.CharField(required=False, max_length=100)
target_id = serializers.IntegerField(required=False)
target_type = serializers.CharField(required=False, max_length=100)
from django.conf.urls import url, include
from courses.stats.views import (
UserActionsView,
)
app_name = 'courses.stats'
urlpatterns = [
url(r'^user-actions/', UserActionsView.as_view(), name='stats'),
url(r'^activity-stream/', include('actstream.urls')),
]
from actstream import action
from rest_framework import views, viewsets, mixins, permissions, status
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from discussion.models import Forum, Topic
from .serializers import UserActionsSerializer
from ..models import Course
class UserActionsView(views.APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request, format=None):
# Only models from this list are registered to be used on actions
allowed_models = {
'Course': Course,
'Topic': Topic,
'Forum': Forum,
}
# Validate incoming data
serializer = UserActionsSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
data = serializer.data
# Get the actual model objects for action and target
action_object = None
target = None
if 'action_object_type' in data:
action_object = allowed_models[data['action_object_type']].objects.get(id=data['action_object_id'])
if 'target_type' in data:
target = allowed_models[data['target_type']].objects.get(id=data['target_id'])
# Save the action
action.send(request.user, verb=data['verb'], action_object=action_object, target=target)
return Response(None, status=status.HTTP_201_CREATED)
......@@ -30,6 +30,10 @@ from courses.classroom.views import (
ClassroomViewSet,
EventViewSet,
)
from courses.stats.views import (
UserActionsView,
)
router = routers.SimpleRouter(trailing_slash=False)
router.register(r'course', CourseViewSet, base_name='course')
......@@ -66,6 +70,9 @@ router.register(r'event', EventViewSet, base_name='event')
app_name = 'courses'
urlpatterns = [
# Stats (Activity Stream related functionality)
url(r'^stats/', include('courses.stats.urls')),
url(r'^course/(?P<course_id>[1-9][0-9]*)/export/$', ExportCourseView.as_view(), name="course_export"),
url(r'^course/import/$', ImportCourseView.as_view(), name="course_import"),
url(r'^', include(router.urls)),
......
......@@ -41,7 +41,7 @@ if sys.argv[-1] == 'tag':
os.system("git push --tags")
sys.exit()
readme = open('README.rst').read()
readme = open('README.md').read()
history = open('HISTORY.rst').read().replace('.. :changelog:', '')
setup(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment