Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ coverage.xml

# Django stuff:
*.log
*.sqlite3

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# virtualenv
venv
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Content Curation

Django app for the Content Curation project.

`// TODO: Make cool stuff`
Empty file.
103 changes: 103 additions & 0 deletions contentcuration/contentcuration/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings
import mptt.fields


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='ContentLicense',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(help_text="Name of license, e.g. 'Creative Commons Share-Alike 2.0'", max_length=255, verbose_name='name')),
],
),
migrations.CreateModel(
name='Node',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')),
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')),
('name', models.CharField(help_text='Name of node to be displayed to the user in the menu', max_length=50, verbose_name='name')),
('published', models.BooleanField(default=False, help_text='If published, students can access this item', verbose_name='Published')),
('deleted', models.BooleanField(default=False, help_text='Indicates that the node has been deleted, and should only be retrievable through the admin backend', verbose_name='Deleted')),
('sort_order', models.FloatField(default=0, help_text='Ascending, lowest number shown first', unique=True, max_length=50, verbose_name='sort order')),
('lft', models.PositiveIntegerField(editable=False, db_index=True)),
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
('level', models.PositiveIntegerField(editable=False, db_index=True)),
],
options={
'verbose_name': 'Topic',
'verbose_name_plural': 'Topics',
},
),
migrations.CreateModel(
name='TopicTree',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(help_text='Displayed to the user', max_length=255, verbose_name='channel name')),
('lft', models.PositiveIntegerField(editable=False, db_index=True)),
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
('level', models.PositiveIntegerField(editable=False, db_index=True)),
('editors', models.ManyToManyField(help_text='Users with edit rights', to=settings.AUTH_USER_MODEL, verbose_name='editors')),
],
options={
'verbose_name': 'Topic tree',
'verbose_name_plural': 'Topic trees',
},
),
migrations.CreateModel(
name='ContentNode',
fields=[
('node_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='contentcuration.Node')),
('author', models.CharField(help_text='Name of the author(s) of book/movie/exercise', max_length=255)),
('license_owner', models.CharField(help_text='Organization of person who holds the essential rights', max_length=255, null=True, blank=True)),
('published_on', models.DateField(help_text='If applicable, state when this work was first published (not on this platform, but for its original publication).', null=True, blank=True)),
('retrieved_on', models.DateTimeField(help_text='Should be automatically filled in when an item is downloaded from its source of origin, either manually by user or automatically by script.', null=True, verbose_name='downloaded on', blank=True)),
('content_file', models.FileField(help_text='Upload video here', null=True, upload_to=b'', blank=True)),
('thumbnail', models.ImageField(help_text='Automatically created when new video is uploaded', null=True, upload_to=b'contents/video/thumbnails/', blank=True)),
('license', models.ForeignKey(verbose_name='license', to='contentcuration.ContentLicense', help_text='License under which the work is distributed')),
],
options={
'abstract': False,
},
bases=('contentcuration.node',),
),
migrations.CreateModel(
name='TopicNode',
fields=[
('node_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='contentcuration.Node')),
('color1', models.CharField(max_length=7)),
('color2', models.CharField(max_length=7)),
('color3', models.CharField(max_length=7)),
],
options={
'abstract': False,
},
bases=('contentcuration.node',),
),
migrations.AddField(
model_name='topictree',
name='root_node',
field=models.ForeignKey(verbose_name='root node', to='contentcuration.Node', help_text='The starting point for the tree, the title of it is the title shown in the menu'),
),
migrations.AddField(
model_name='node',
name='parent',
field=mptt.fields.TreeForeignKey(related_name='children', blank=True, to='contentcuration.Node', null=True),
),
migrations.AlterUniqueTogether(
name='node',
unique_together=set([('parent', 'name')]),
),
]
Empty file.
216 changes: 216 additions & 0 deletions contentcuration/contentcuration/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
from django.utils.translation import ugettext as _

class TopicTree(MPTTModel):
"""Base model for all channels"""

name = models.CharField(
max_length=255,
verbose_name=_("channel name"),
help_text=_("Displayed to the user"),
)
editors = models.ManyToManyField(
'auth.User',
verbose_name=_("editors"),
help_text=_("Users with edit rights"),
)
root_node = models.ForeignKey(
'Node',
verbose_name=_("root node"),
help_text=_(
"The starting point for the tree, the title of it is the "
"title shown in the menu"
),
)

class Meta:
verbose_name = _("Topic tree")
verbose_name_plural = _("Topic trees")


class Node(MPTTModel):
"""
By default, all nodes have a title and can be used as a topic.
"""

created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))

parent = TreeForeignKey('self', null=True, blank=True, related_name='children')

name = models.CharField(
max_length=50,
verbose_name=_("name"),
help_text=_("Name of node to be displayed to the user in the menu"),
)

published = models.BooleanField(
default=False,
verbose_name=_("Published"),
help_text=_("If published, students can access this item"),
)

deleted = models.BooleanField(
default=False,
verbose_name=_("Deleted"),
help_text=_(
"Indicates that the node has been deleted, and should only "
"be retrievable through the admin backend"
),
)

sort_order = models.FloatField(
max_length=50,
unique=True,
default=0,
verbose_name=_("sort order"),
help_text=_("Ascending, lowest number shown first"),
)

@property
def has_draft(self):
return self.draft_set.all().exists()

@property
def get_draft(self):
"""
NB! By contract, only one draft should always exist per node, this is
enforced by the OneToOneField relation.
:raises: Draft.DoesNotExist and Draft.MultipleObjectsReturned
"""
return Draft.objects.get(publish_in=self)

class MPTTMeta:
order_insertion_by = ['sort_order']

class Meta:
verbose_name = _("Topic")
verbose_name_plural = _("Topics")
# Do not allow two nodes with the same name on the same level
unique_together = ('parent', 'name')


class TopicNode(Node):
# Rename the colors when they have decided roles in the UI
# Length 7 because hex codes?
color1 = models.CharField(
max_length=7
)

color2 = models.CharField(
max_length=7
)

color3 = models.CharField(
max_length=7
)


class ContentNode(Node):
"""
Model for content data nodes, which will be stored as leaves only
"""

author = models.CharField(
max_length=255,
help_text=_("Name of the author(s) of book/movie/exercise"),
)

license_owner = models.CharField(
max_length=255,
blank=True,
null=True,
help_text=_("Organization of person who holds the essential rights"),
)

published_on = models.DateField(
null=True,
blank=True,
help_text=_(
"If applicable, state when this work was first published (not on "
"this platform, but for its original publication)."
),
)

retrieved_on = models.DateTimeField(
null=True,
blank=True,
verbose_name=_("downloaded on"),
help_text=_(
"Should be automatically filled in when an item is downloaded "
"from its source of origin, either manually by user or "
"automatically by script."
),
)

content_file = models.FileField(
blank=True,
null=True,
# TODO
# upload_to='contents/video/thumbnails/',
help_text=_("Upload video here"),
)

thumbnail = models.ImageField(
blank=True,
null=True,
upload_to='contents/video/thumbnails/',
help_text=_("Automatically created when new video is uploaded")
)

license = models.ForeignKey(
'ContentLicense',
verbose_name=_("license"),
help_text=_("License under which the work is distributed"),
)


# If we decide to subclass Content:

# class ContentVideo(Content):
# """
# Model for video data
# """

# video_file = models.FileField(
# blank=True,
# null=True,
# upload_to='contents/video/thumbnails/',
# verbose_name=_("video file"),
# help_text=_("Upload video here"),
# )

# thumbnail = models.ImageField(
# null=True,
# upload_to='contents/video/thumbnails/',
# help_text=_("Automatically created when new video is uploaded")
# )


# class ContentPDF(Content):
# """
# Model for video data
# """

# pdf_file = models.FileField(
# blank=True,
# null=True,
# upload_to='contents/video/thumbnails/',
# verbose_name=_("video file"),
# help_text=_("Upload video here"),
# )


# class Exercise(Content):
# """
# Model for Exercise data
# """


class ContentLicense(models.Model):
name = models.CharField(
max_length=255,
verbose_name=_("name"),
help_text=_("Name of license, e.g. 'Creative Commons Share-Alike 2.0'")
)
20 changes: 20 additions & 0 deletions contentcuration/contentcuration/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from contentcuration.models import * # TODO: Change this later?
from rest_framework import serializers

class ContentSerializer(serializers.ModelSerializer):
class Meta:
model = ContentNode
# TODO: content_file
fields = ('created', 'modified', 'parent', 'name', 'published', 'sort_order',
'author', 'license_owner', 'license')

class TopicSerializer(serializers.ModelSerializer):
class Meta:
model = TopicNode
fields = ('created', 'modified', 'parent', 'name', 'published', 'sort_order',
'color1', 'color2', 'color3')

class LicenseSerializer(serializers.ModelSerializer):
class Meta:
model = ContentLicense
fields = ('name')
Loading