Commit d6331161 authored by svilayphiou's avatar svilayphiou

Merge branch 'django2.0' into 'master'

Django2.0

See merge request !7
parents 7116b337 dc68246c
......@@ -37,26 +37,25 @@ Infrastructures entrelacées, an exhibition by the collective Artivistic at SKOL
## Installation instructions
Requires Django 1.5
Requires Django 2.0
First create and install a virtual environment [1]. Then:
sudo aptitude install python-dev libxml2-dev libxslt-dev libz-dev
pip install "django<1.6" south Markdown html5tidy python-dateutil rdflib pytz six isodate lxml
pip install "django<2.1" django-markdown python-dateutil rdflib
# old pip install html5tidy pytz six isodate lxml
pip install https://github.com/devjones/PyEtherpadLite/archive/master.zip
pip install https://github.com/aleray/markdown-figures/archive/master.zip
mkdir -p ~/src/
cd ~/src
git clone http://gitlab.constantvzw.org/osp/tools.ethertoff.git
# Or use cloning over ssh (requires account):
# git@gitlab.constantvzw.org:osp/tools.ethertoff.git
cd tools.ethertoff # [2]
cd relearn
cd ethertoff
cp local_settings.py.example local_settings.py
# Change database details in local_settings.py
cd ..
python manage.py syncdb
python manage.py migrate etherpadlite
# python manage.py syncdb
python manage.py migrate
Change the info of your domain name and website name in the Sites section on
<http://localhost:8000/admin>. **Do not add "http://" in your domain name,
......@@ -74,19 +73,25 @@ And then do the following (replace the "domain" and "name" with your own info):
site = Site.objects.create(domain='example.com', name='example.com')
site.save()
--> and then install etherpad
## Install Etherpad-lite
mkdir -p ~/src
cd ~/src
git clone https://github.com/ether/etherpad-lite.git
# --> install node js
## --> install node js
Install Make:
sudo aptitude install build-essentials
Linux Binaries (.tar.gz) from http://nodejs.org/download/
## Launch Etherpad-lite
run Etherpad with:
~/src/etherpad-lite/bin/run.sh
......@@ -95,7 +100,11 @@ Your Etherpad is running at http://127.0.0.1:9001/
In Etherpad’s folder, you will find a file called APIKEY.txt
you need its contents later
## Launch Ethertoff
Run the server:
python manage.py runserver
......@@ -108,35 +117,29 @@ Now, on the Django admin:
url: http://127.0.0.1:9001/
# if on a server
url: http://domainname/ether/
api_key: the contents of the file APIKEY.txt
api_key: the contents of the file APIKEY.txt in Etherpad files
Go back to the admin home, and then add a new group:
Auth > Groups > Add
Go back to the admin home, and then add the superuser (and all needed users)
to the group you just created
Go back to the admin home, and then add the superuser (and all needed users) to the group you just created
Auth > Users
Go back to the admin home, and then create an Etherpad Group based upon the group and the server you just created.
Etherpadlite > Groups > Add
Now relearn is served at http://127.0.0.1:8000/ locally, or on your domain
name on a server.
Now Ethertoff is served at http://127.0.0.1:8000/ locally, or on your domain name on a server.
You can set the site name, that appears on the header, in the ‘sites’ app in the admin.
- - -
[1] Something like:
[^1]: Something like:
mkdir -p ~/venvs/
cd ~/venvs/
virtualenv relearn
source ~/venvs/relearn/bin/activate
[2] For those running the Virtual Machine from the relearn summer school:
cd ~/relearn/relearn.be/
virtualenv ethertoff
source ~/venvs/ethertoff/bin/activate
- - -
......@@ -148,15 +151,15 @@ example.com / -> django
/ether/ -> etherpad
/static/ -> django static files
To test if everything is working, you can use screen to run gunicorn and
etherpad scripts at the same time, and then use a daemon like Supervisor to run them in the
background.
To test if everything is working, you can use screen to run gunicorn and Etherpad scripts at the same time, and then use a daemon like Supervisor to run them in the background.
## MYSQL
pip install "distribute>0.6.24"
sudo aptitude install libmysqlclient-dev python-dev
pip install MySQL-python
# pip install "distribute>0.6.24"
sudo aptitude install libmysqlclient-dev python-dev
pip install MySQL-python mysqlclient
## DJANGO
......@@ -173,10 +176,10 @@ folder /static/.
pip install gunicorn
cd /etc/nginx/sites-available/
# (edit nginx config file)
sudo vim relearn/
sudo vim ethertoff.conf
cd ../sites-enabled/
sudo ln -s ../sites-available/relearn
cd relearn_directory/
sudo ln -s ../sites-available/ethertoff
cd ethertoff_directory/
# (edit gunicorn config file)
vim run.sh
chmod +x run.sh
......@@ -186,6 +189,8 @@ folder /static/.
To run the server in the background, use Supervisor daemon.
## ETHERPAD
Etherpad, finally, runs as its own server. You probably need to use
a supervisor such as supervisord to make sure it keeps running.
......@@ -194,6 +199,8 @@ is not intended for use on servers. Finally, you will need to reverse
proxy the Etherpad process from your main web server, mapping it to
a folder such as /ether/.
## SUPERVISOR
To run django and etherpad in the background.
......
......@@ -5,11 +5,11 @@ from django.contrib import admin
from etherpadlite.models import *
class PadAuthorAdmin(admin.ModelAdmin):
list_display = ('__unicode__',)
list_display = ('__str__',)
class PadAdmin(admin.ModelAdmin):
list_display = ('__unicode__',)
list_display = ('__str__',)
readonly_fields = ('name',)
exclude = ('display_name',)
......
......@@ -11,4 +11,4 @@ class PadCreate(forms.Form):
class GroupCreate(forms.ModelForm):
class Meta:
model = Group
exclude = ('permissions')
exclude = ('permissions',)
This diff is collapsed.
# Generated by Django 2.1.1 on 2018-09-19 13:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('etherpadlite', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='pad',
name='display_slug',
field=models.CharField(blank=True, max_length=255, unique=True, verbose_name='Name as used in URL (use :: for namespacing)'),
),
]
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Pad.name'
db.alter_column(u'etherpadlite_pad', 'name', self.gf('django.db.models.fields.CharField')(max_length=50))
def backwards(self, orm):
# Changing field 'Pad.name'
db.alter_column(u'etherpadlite_pad', 'name', self.gf('django.db.models.fields.CharField')(max_length=256))
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'etherpadlite.pad': {
'Meta': {'ordering': "['display_slug', 'name']", 'object_name': 'Pad'},
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'display_slug': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadGroup']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadServer']"})
},
u'etherpadlite.padauthor': {
'Meta': {'object_name': 'PadAuthor'},
'authorID': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'authors'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['etherpadlite.PadGroup']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadServer']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'etherpadlite.padgroup': {
'Meta': {'object_name': 'PadGroup'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.Group']"}),
'groupID': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadServer']"})
},
u'etherpadlite.padserver': {
'Meta': {'object_name': 'PadServer'},
'apikey': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
'url': ('django.db.models.fields.URLField', [], {'max_length': '256'})
}
}
complete_apps = ['etherpadlite']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
class Migration(DataMigration):
def forwards(self, orm):
"Write your forwards methods here."
# Note: Don't use "from appname.models import ModelName".
# Use orm.ModelName to refer to models in this application,
# and orm['appname.ModelName'] for models in other applications.
# and orm['appname.ModelName'] for models in other applications.
for pad in orm.Pad.objects.all():
pad.name = pad.name[:42]
pad.save()
def backwards(self, orm):
"Write your backwards methods here."
raise RuntimeError("Cannot reverse this migration.")
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'etherpadlite.pad': {
'Meta': {'ordering': "['display_slug', 'name']", 'object_name': 'Pad'},
'display_name': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'display_slug': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadGroup']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadServer']"})
},
u'etherpadlite.padauthor': {
'Meta': {'object_name': 'PadAuthor'},
'authorID': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'authors'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['etherpadlite.PadGroup']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadServer']"}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'etherpadlite.padgroup': {
'Meta': {'object_name': 'PadGroup'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.Group']"}),
'groupID': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['etherpadlite.PadServer']"})
},
u'etherpadlite.padserver': {
'Meta': {'object_name': 'PadServer'},
'apikey': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
'url': ('django.db.models.fields.URLField', [], {'max_length': '256'})
}
}
complete_apps = ['etherpadlite']
symmetrical = True
......@@ -3,12 +3,12 @@
from django.db import models
from django.db.models.signals import pre_delete
from django.contrib.auth.models import User, Group
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from py_etherpad import EtherpadLiteClient
from relearn.templatetags.wikify import dewikify
from ethertoff.templatetags.wikify import dewikify
import string
import random
......@@ -27,7 +27,7 @@ class PadServer(models.Model):
class Meta:
verbose_name = _('server')
def __unicode__(self):
def __str__(self):
return self.url
@property
......@@ -41,15 +41,15 @@ class PadServer(models.Model):
class PadGroup(models.Model):
"""Schema and methods for etherpad-lite groups
"""
group = models.ForeignKey(Group)
group = models.ForeignKey(Group, models.PROTECT)
groupID = models.CharField(max_length=256, blank=True)
server = models.ForeignKey(PadServer)
server = models.ForeignKey(PadServer, models.PROTECT)
class Meta:
verbose_name = _('group')
def __unicode__(self):
return self.group.__unicode__()
def __str__(self):
return self.group.__str__()
@property
def epclient(self):
......@@ -62,8 +62,9 @@ class PadGroup(models.Model):
return ''.join(random.choice(chars) for x in range(size))
def EtherMap(self):
print(self.group)
result = self.epclient.createGroupIfNotExistsFor(
self.group.__unicode__() + self._get_random_id() +
u"%s" % (self.group) + self._get_random_id() +
self.group.id.__str__()
)
self.groupID = result['groupID']
......@@ -104,9 +105,9 @@ pre_delete.connect(groupDel, sender=Group)
class PadAuthor(models.Model):
"""Schema and methods for etherpad-lite authors
"""
user = models.ForeignKey(User)
user = models.ForeignKey(User, models.PROTECT)
authorID = models.CharField(max_length=256, blank=True)
server = models.ForeignKey(PadServer)
server = models.ForeignKey(PadServer, models.PROTECT)
group = models.ManyToManyField(
PadGroup,
blank=True,
......@@ -130,14 +131,14 @@ class PadAuthor(models.Model):
return full_name
return self.user.username
def __unicode__(self):
def __str__(self):
return self.full_name_with_prefix()
def EtherMap(self):
epclient = EtherpadLiteClient(self.server.apikey, self.server.apiurl)
result = epclient.createAuthorIfNotExistsFor(
self.user.id.__str__(),
name=self.__unicode__()
name=self.__str__()
)
self.authorID = result['authorID']
return result
......@@ -161,25 +162,38 @@ class Pad(models.Model):
"""Schema and methods for etherpad-lite pads
"""
name = models.CharField(max_length=50)
display_slug = models.CharField(max_length=256, blank=True, verbose_name="Name as used in URL (use :: for namespacing)")
display_slug = models.CharField(max_length=255, blank=True, verbose_name="Name as used in URL (use :: for namespacing)", unique=True)
# I’m putting this back. We don’t use it anymore, but putting in the migration is
# more hassle then it’s worth
display_name = models.CharField(max_length=256, blank=True, verbose_name=u"Name as used in Display (use → for namespacing)")
server = models.ForeignKey(PadServer)
group = models.ForeignKey(PadGroup)
server = models.ForeignKey(PadServer, models.PROTECT)
group = models.ForeignKey(PadGroup, models.PROTECT)
def __unicode__(self):
def __str__(self):
return self.display_slug
def get_absolute_url(self):
return reverse('relearn.views.xhtml', args=[self.display_slug.replace('.md','')])
#return reverse('ethertoff.views.xhtml', args=[self.display_slug.replace('.md','')])
return ('pad-read', (), {'slug': self.display_slug.replace('.md','')})
@property
def padid(self):
return "%s$%s" % (self.group.groupID, self.name)
@property
def getLastEdited(self):
from datetime import datetime
import email.utils
timestamp = self.epclient.getLastEdited(self.padid)
dt = datetime.fromtimestamp(timestamp['lastEdited']/1000)
return email.utils.format_datetime(dt)
@property
def getFirstLines(self):
return "%s" % (self.epclient.getText(self.padid)['text'][:280])
@property
def epclient(self):
return EtherpadLiteClient(self.server.apikey, self.server.apiurl)
......
......@@ -25,7 +25,7 @@ class PadServerTestCase(unittest.TestCase):
def testBasics(self):
self.assertTrue(isinstance(self.server, PadServer))
self.assertEqual(self.server.__unicode__(), TS['url'])
self.assertEqual(self.server.__str__(), TS['url'])
class PadGroupTestCase(unittest.TestCase):
......@@ -46,7 +46,7 @@ class PadGroupTestCase(unittest.TestCase):
def testBasics(self):
self.assertTrue(isinstance(self.padGroup, PadGroup))
self.assertEqual(self.padGroup.__unicode__(), self.group.__unicode__())
self.assertEqual(self.padGroup.__str__(), self.group.__str__())
def tearDown(self):
self.padGroup.delete()
......@@ -75,7 +75,7 @@ class PadAuthorTestCase(unittest.TestCase):
def testBasics(self):
self.assertTrue(isinstance(self.author, PadAuthor))
self.assertEqual(self.author.__unicode__(), self.user.__unicode__())
self.assertEqual(self.author.__str__(), self.user.__str__())
def tearDown(self):
self.padGroup.delete()
......@@ -109,7 +109,7 @@ class PadTestCase(unittest.TestCase):
def testBasics(self):
self.assertTrue(isinstance(self.pad, Pad))
self.assertEqual(self.pad.__unicode__(), self.pad.name)
self.assertEqual(self.pad.__str__(), self.pad.name)
def tearDown(self):
self.padGroup.delete()
......
from django.contrib.auth import views as auth_views
from django.conf.urls.defaults import patterns, url
from etherpadlite.models import *
urlpatterns = patterns(
'',
url(r'^$', 'django.contrib.auth.views.login',
urlpatterns = [
#path('', 'django.contrib.auth.views.login',
#{'template_name': 'etherpad-lite/login.html'}, name='login'),
path('', auth_views.LoginView.as_view(),
{'template_name': 'login.html'}, name='login'),
path('etherpad', 'django.contrib.auth.views.login',
{'template_name': 'etherpad-lite/login.html'}),
url(r'^etherpad$', 'django.contrib.auth.views.login',
{'template_name': 'etherpad-lite/login.html'}),
url(r'^logout$', 'django.contrib.auth.views.logout',
path('logout', 'django.contrib.auth.views.logout',
{'template_name': 'etherpad-lite/logout.html'}),