Skip to content
Open
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
Empty file added ployst/core/blips/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions ployst/core/blips/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.contrib import admin

from .models import Blip, Stream, Tag


class StreamInline(admin.TabularInline):
model = Blip.streams.through


class BlipAdmin(admin.ModelAdmin):
inlines = (StreamInline,)

admin.site.register(Blip, BlipAdmin)
admin.site.register(Stream)
admin.site.register(Tag)
55 changes: 55 additions & 0 deletions ployst/core/blips/blip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import re

# import yaml


LEXEMS = {
'name': r'[\w\-_]+',
'key_separator': ':',
}

PATTERNS = {
'streams': r'\>(?P<stream>{name})',
'mentions': r'@(?P<mention>{name})',
'privates': r'!(?P<private>{name})',
'tags': r'#(?P<tag>{name}(?:{key_separator}{name})?)',
}

COMPILED_PATTERNS = {
key: re.compile(value.format(**LEXEMS), flags=re.UNICODE)
for key, value in PATTERNS.items()
}


class Blip(object):

@classmethod
def from_text(cls, text):
blip = cls()
blip.text = text
for attr, pattern in COMPILED_PATTERNS.items():
setattr(blip, attr, pattern.findall(text))
return blip.populate_metadata()

"""
@classmethod
def from_yaml(cls, yaml_text):
parsed = yaml.load(yaml_text)
blip = cls()
blip.__dict__ = parsed
return blip.populate_metadata()
"""

def populate_metadata(self):
self.metadata = {}
for tag in self.tags:
try:
key, value = tag.split(LEXEMS['key_separator'])
except:
pass
else:
self.metadata[key] = value
return self

def __getitem__(self, key):
return self.metadata[key]
65 changes: 65 additions & 0 deletions ployst/core/blips/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

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


class Migration(migrations.Migration):

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

operations = [
migrations.CreateModel(
name='Blip',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=256)),
('text', models.TextField()),
('as_persona', models.ForeignKey(to='blips.Blip', null=True)),
('author', models.ForeignKey(related_name='blips', to=settings.AUTH_USER_MODEL)),
('mentions', models.ManyToManyField(related_name='mentioned_in', to=settings.AUTH_USER_MODEL)),
('privates', models.ManyToManyField(related_name='private_in', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Metadata',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('value', models.CharField(max_length=256)),
('blip', models.ForeignKey(to='blips.Blip')),
],
),
migrations.CreateModel(
name='Stream',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=256)),
('owner', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Tag',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=256)),
],
),
migrations.AddField(
model_name='metadata',
name='tag',
field=models.ForeignKey(to='blips.Tag'),
),
migrations.AddField(
model_name='blip',
name='streams',
field=models.ManyToManyField(to='blips.Stream'),
),
migrations.AddField(
model_name='blip',
name='tags',
field=models.ManyToManyField(to='blips.Tag'),
),
]
Empty file.
39 changes: 39 additions & 0 deletions ployst/core/blips/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from django.db import models

from ployst.core.accounts.models import User


class Stream(models.Model):
owner = models.ForeignKey(User)
name = models.CharField(max_length=256)

def __unicode__(self):
return u'>{}.{}'.format(self.owner.username, self.name)


class Tag(models.Model):
name = models.CharField(max_length=256)

def __unicode__(self):
return u'#{}'.format(self.name)


class Metadata(models.Model):
tag = models.ForeignKey(Tag)
blip = models.ForeignKey('blips.Blip')
value = models.CharField(max_length=256)


class Blip(models.Model):
author = models.ForeignKey(User, related_name='blips')
as_persona = models.ForeignKey('blips.Blip', null=True)
title = models.CharField(max_length=256)
text = models.TextField()
streams = models.ManyToManyField(Stream)
mentions = models.ManyToManyField(User, related_name='mentioned_in')
privates = models.ManyToManyField(User, related_name='private_in')
tags = models.ManyToManyField(Tag)
# metadata = models.ManyToManyField(Tag, through=Metadata)

def __unicode__(self):
return self.text
15 changes: 15 additions & 0 deletions ployst/core/blips/parsers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from rest_framework.parsers import BaseParser


class PlainTextParser(BaseParser):
"""
Plain text parser.
"""

media_type = 'text/plain'

def parse(self, stream, media_type=None, parser_context=None):
"""
Simply return a string representing the body of the request.
"""
return {'text': stream.read()}
47 changes: 47 additions & 0 deletions ployst/core/blips/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from rest_framework import serializers

from ployst.core.accounts.models import User

from .blip import Blip as BlipParser
from .models import Blip, Stream, Tag


class BlipSerializer(serializers.ModelSerializer):
text = serializers.CharField()
streams = serializers.SlugRelatedField(
many=True, read_only=True, slug_field='name')
tags = serializers.SlugRelatedField(
many=True, read_only=True, slug_field='name')
mentions = serializers.SlugRelatedField(
many=True, read_only=True, slug_field='username')
privates = serializers.SlugRelatedField(
many=True, read_only=True, slug_field='username')

class Meta:
model = Blip
fields = ('id', 'text', 'streams', 'tags', 'mentions', 'privates')

def create(self, validated_data):
request = self.context.get('request', None)
user = request.user
parsed = BlipParser.from_text(**validated_data)
blip = Blip.objects.create(
author=user,
text=parsed.text,
)

for name in parsed.tags:
tag, _ = Tag.objects.get_or_create(name=name)
blip.tags.add(tag)

for name in parsed.streams:
stream, _ = Stream.objects.get_or_create(name=name, owner=user)
blip.streams.add(stream)

for attr in ['privates', 'mentions']:
collection = getattr(blip, attr)
for name in getattr(parsed, attr):
user_ref = User.objects.get(username=name)
collection.add(user_ref)

return blip
Empty file.
66 changes: 66 additions & 0 deletions ployst/core/blips/test/test_blip_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
from unittest import TestCase
from ..blip import Blip

FULL = u"""
Something to consider.

Hey here is a link https://python.org from @orne #language:python !alex
>barrobés >read-later
""".strip()

TAGS = u"Python rules #language:python #programming #rating:5 I love it"


class TestBlipParseText(TestCase):

def test_parse_full(self):
blip = Blip.from_text(FULL)
self.assertEqual(blip.mentions, [u'orne'])
self.assertEqual(blip.privates, [u'alex'])
self.assertEqual(blip.streams, [u'barrobés', u'read-later'])
self.assertEqual(blip.tags, [u'language:python'])

def test_parse_tags(self):
blip = Blip.from_text(TAGS)
self.assertEqual(blip.mentions, [])
self.assertEqual(blip.privates, [])
self.assertEqual(blip.streams, [])
self.assertEqual(blip.tags,
[u'language:python', 'programming', 'rating:5'])

def test_parse_metadata(self):
blip = Blip.from_text(TAGS)
self.assertEqual(blip.metadata, {'language': 'python', 'rating': '5'})
self.assertEqual(blip['language'], 'python')
self.assertEqual(blip['rating'], '5')


YAML_FULL = u"""
title: My blip
text: "Here is a blip about a nice programming language"
mentions:
- orne
privates:
- alex
tags:
- language:python
- rating:5
- programming
streams:
- barrobés
- read-later
""".strip()


"""
class TestBlipParseYaml(TestCase):

def test_parse_full(self):
blip = Blip.from_yaml(YAML_FULL)
self.assertEqual(blip['language'], 'python')
self.assertEqual(blip['rating'], '5')
self.assertEqual(blip.mentions, [u'orne'])
self.assertEqual(blip.privates, [u'alex'])
self.assertEqual(blip.streams, [u'barrobés', u'read-later'])
"""
13 changes: 13 additions & 0 deletions ployst/core/blips/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.conf.urls import url, patterns, include

from rest_framework import routers
from . import views

router = routers.SimpleRouter(trailing_slash=False)
router.register(r'blip', views.BlipViewSet, base_name='blip')


urlpatterns = patterns(
'',
url(r'^', include(router.urls)),
)
28 changes: 28 additions & 0 deletions ployst/core/blips/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import django_filters
from rest_framework.viewsets import ModelViewSet
from rest_framework.parsers import JSONParser

from .models import Blip
from .parsers import PlainTextParser
from .serializers import BlipSerializer


class BlipFilter(django_filters.FilterSet):
stream = django_filters.CharFilter(name="streams__name")
tag = django_filters.CharFilter(name="tags__name")
mention = django_filters.CharFilter(name="mentions__username")
private = django_filters.CharFilter(name="privates__username")

class Meta:
model = Blip
fields = ['author', 'stream', 'tag', 'mention', 'private']


class BlipViewSet(ModelViewSet):
"""
A simple ViewSet for blips.
"""
queryset = Blip.objects.all()
serializer_class = BlipSerializer
parser_classes = (JSONParser, PlainTextParser)
filter_class = BlipFilter
2 changes: 2 additions & 0 deletions ployst/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

url(r'^accounts/',
include('ployst.core.accounts.urls', namespace='accounts')),
url(r'^blips/',
include('ployst.core.blips.urls', namespace='blips')),
url(r'^builds/',
include('ployst.core.builds.urls', namespace='builds')),
url(r'^features/',
Expand Down
3 changes: 2 additions & 1 deletion ployst/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
'ployst.core.features', # planning: stories, bugs, features...
'ployst.core.repos', # version control: repos, branches...
'ployst.core.builds', # continuous integration: build results...
'ployst.core.blips', # ployst2 prototyping
'ployst.ui', # The main Ployst UI

# Providers
Expand All @@ -73,7 +74,7 @@


# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
'default': {
Expand Down