Commit f1101d2e authored by onny's avatar onny

further form validation

parent cd26c412
......@@ -16,7 +16,7 @@ Including another URLconf
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import routers
from openart.views import index_page, add_page, artists_page, projects_page, entries_page
from openart.views import index_page, add_page, artists_page, projects_page, entries_page, artist_page
from openart.views import ArtistViewSet, ProjectViewSet, EntryViewSet
# Routers provide an easy way of automatically determining the URL conf.
......@@ -30,6 +30,7 @@ urlpatterns = [
url(r'^$', index_page),
url(r'^add/', add_page),
url(r'^artists/', artists_page),
url(r'^en/(.*)$', artist_page),
url(r'^projects/', projects_page),
url(r'^entries/', entries_page),
url(r'^api/', include(router.urls)),
......
from django import forms
#from django.forms import ModelForm, HiddenInput
from .models import Artist, Project, Entry
from .models import Artist, Project, Entry, Media
#alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed.')
alphanum_regex = '[A-Za-z-ÁÀȦÂÄǞǍĂĀÃÅǺǼǢĆĊĈČĎḌḐḒÉÈĖÊËĚĔĒẼE̊ẸǴĠĜǦĞG̃ĢĤḤáàȧâäǟǎăāãåǻǽǣćċĉčďḍḑḓéèėêëěĕēẽe̊ẹǵġĝǧğg̃ģĥḥÍÌİÎÏǏĬĪĨỊĴĶǨĹĻĽĿḼM̂M̄ʼNŃN̂ṄN̈ŇN̄ÑŅṊÓÒȮȰÔÖȪǑŎŌÕȬŐỌǾƠíìiîïǐĭīĩịĵķǩĺļľŀḽm̂m̄ʼnńn̂ṅn̈ňn̄ñņṋóòôȯȱöȫǒŏōõȭőọǿơP̄ŔŘŖŚŜṠŠȘṢŤȚṬṰÚÙÛÜǓŬŪŨŰŮỤẂẀŴẄÝỲŶŸȲỸŹŻŽẒǮp̄ŕřŗśŝṡšşṣťțṭṱúùûüǔŭūũűůụẃẁŵẅýỳŷÿȳỹźżžẓǯßœŒçÇ0-9\s]*'
signatory_regex = '[A-Z0-9-_]*'
class ArtistForm(forms.ModelForm):
class Meta:
model = Artist
fields = ['name',]
widgets = {
'name': forms.TextInput(attrs={'v-model': 'artist.name'})
'name': forms.TextInput(attrs={
'v-model': 'artist.name',
'pattern': alphanum_regex
})
}
class ProjectForm(forms.ModelForm):
......@@ -18,8 +21,14 @@ class ProjectForm(forms.ModelForm):
fields = ['artist', 'name', 'city', 'datefrom', 'dateto']
widgets = {
'artist': forms.Select(attrs={'v-model': 'artist.id'}),
'name': forms.TextInput(attrs={'v-model': 'project.name'}),
'city': forms.TextInput(attrs={'v-model': 'project.city'}),
'name': forms.TextInput(attrs={
'v-model': 'project.name',
'pattern': alphanum_regex
}),
'city': forms.TextInput(attrs={
'v-model': 'project.city',
'pattern': alphanum_regex
}),
'datefrom': forms.DateTimeInput(attrs={'type': 'date', 'v-model': 'project.datefrom'}),
'dateto': forms.DateTimeInput(attrs={'type': 'date', 'v-model': 'project.dateto'})
}
......@@ -30,9 +39,24 @@ class EntryForm(forms.ModelForm):
fields = ['project', 'signatory', 'description', 'dimension', 'visibility', 'type']
widgets = {
'project': forms.Select(attrs={'v-model': 'project.id'}),
'signatory': forms.TextInput(attrs={'v-model': 'entry.signatory'}),
'description': forms.TextInput(attrs={'v-model': 'entry.description'}),
'signatory': forms.TextInput(attrs={
'v-model': 'entry.signatory',
'pattern': signatory_regex
}),
'description': forms.TextInput(attrs={
'v-model': 'entry.description',
'pattern': alphanum_regex
}),
'dimension': forms.TextInput(attrs={'v-model': 'entry.dimension'}),
'visibility': forms.CheckboxInput(attrs={'v-model': 'entry.visibility'}),
'type': forms.Select(attrs={'v-model': 'entry.type'})
}
class MediaForm(forms.ModelForm):
class Meta:
model = Media
fields = ['file', 'entry']
widgets = {
'file': forms.FileInput, #(attrs={'v-model': 'media.file'}), # FIXME
'entry': forms.Select(attrs={'v-model': 'entry.id'})
}
from __future__ import unicode_literals
import re
from django.db import models
from django.core.validators import RegexValidator
alphanum_regex = RegexValidator(
regex='^[A-Za-z-ÁÀȦÂÄǞǍĂĀÃÅǺǼǢĆĊĈČĎḌḐḒÉÈĖÊËĚĔĒẼE̊ẸǴĠĜǦĞG̃ĢĤḤáàȧâäǟǎăāãåǻǽǣćċĉčďḍḑḓéèėêëěĕēẽe̊ẹǵġĝǧğg̃ģĥḥÍÌİÎÏǏĬĪĨỊĴĶǨĹĻĽĿḼM̂M̄ʼNŃN̂ṄN̈ŇN̄ÑŅṊÓÒȮȰÔÖȪǑŎŌÕȬŐỌǾƠíìiîïǐĭīĩịĵķǩĺļľŀḽm̂m̄ʼnńn̂ṅn̈ňn̄ñņṋóòôȯȱöȫǒŏōõȭőọǿơP̄ŔŘŖŚŜṠŠȘṢŤȚṬṰÚÙÛÜǓŬŪŨŰŮỤẂẀŴẄÝỲŶŸȲỸŹŻŽẒǮp̄ŕřŗśŝṡšşṣťțṭṱúùûüǔŭūũűůụẃẁŵẅýỳŷÿȳỹźżžẓǯßœŒçÇ0-9\s]*$',
message='Input must be Alphanumeric',
code='invalid_input_chars'
)
signatory_regex = RegexValidator(
regex='^[A-Z0-9\-\_]*$',
message='Invalid chars in Signatatory',
code='invalid_signatory'
)
class Artist(models.Model):
name = models.CharField(max_length=100, blank=False)
name = models.CharField(
max_length=100,
blank=False,
validators=[alphanum_regex,]
)
slug = models.CharField(max_length=100)
# Generate slug field
def save(self, *args, **kwargs):
count = 1
while Artist.objects.filter(name=self.name).exists():
self.name = re.sub(' \(.*?\)','', self.name) + f" ({count})"
count = count + 1
slug = self.name.lower().replace(' ','-')
self.slug = re.sub('[()]','', slug) # FIXME
print(self.slug)
super(Artist, self).save(*args, **kwargs)
def __str__(self):
return self.name
class Project(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
name = models.CharField(max_length=100, blank=False)
city = models.CharField(max_length=100)
datefrom = models.DateField()
dateto = models.DateField()
name = models.CharField(
max_length=100,
blank=False,
validators=[alphanum_regex,])
city = models.CharField(
max_length=100,
blank=True,
validators=[alphanum_regex,])
datefrom = models.DateField(
blank=True,
null=True
)
dateto = models.DateField(
blank=True,
null=True
)
def __str__(self):
return self.name
class Entry(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
signatory = models.CharField(max_length=100)
description = models.CharField(max_length=100)
dimension = models.CharField(max_length=100)
visibility = models.BooleanField(default=False)
signatory = models.CharField(
max_length=100,
validators=[signatory_regex,],
unique=True
)
description = models.CharField(
max_length=100,
blank=True
)
dimension = models.CharField(
max_length=100,
blank=True
)
visibility = models.BooleanField(
default=False
)
TYPE_CHOICES = (
('VP', 'Vintage Print'),
......@@ -34,7 +87,17 @@ class Entry(models.Model):
('MI', 'Microfiche'),
('AK', 'Akte')
)
type = models.CharField(max_length=20,choices=TYPE_CHOICES)
type = models.CharField(
max_length=20,
choices=TYPE_CHOICES
)
def __str__(self):
return self.signatory
class Media(models.Model):
file = models.FileField(
blank=False,
upload_to='uploads'
)
entry = models.ForeignKey(Entry, on_delete=models.CASCADE)
......@@ -3,18 +3,27 @@ from django.http import HttpResponse
from .models import Artist, Project, Entry
from rest_framework import viewsets
from .serializers import ArtistSerializer, ProjectSerializer, ProjectReadSerializer, EntrySerializer, EntryReadSerializer
from .forms import ArtistForm, ProjectForm, EntryForm
from .forms import ArtistForm, ProjectForm, EntryForm, MediaForm
from django.conf import settings
def index_page(request):
html = TemplateResponse(request, 'index.html')
return HttpResponse(html.render())
def add_page(request):
if request.method == 'POST':
save_path = os.path.join(settings.MEDIA_ROOT, 'uploads', request.FILES['file'])
path = default_storage.save(save_path, request.FILES['file'])
document = Media.objects.create(file=path, entry=1) # FIXME get entry
return True
context = {}
context['artist'] = Artist.objects.all()
context['artist_form'] = ArtistForm
context['project_form'] = ProjectForm
context['entry_form'] = EntryForm
context['media_form'] = MediaForm
html = TemplateResponse(request, 'add.html', context)
return HttpResponse(html.render())
......@@ -26,6 +35,13 @@ def artists_page(request):
html = TemplateResponse(request, 'artists.html', context)
return HttpResponse(html.render())
def artist_page(request, slug):
context = {}
context['artist'] = Artist.objects.get(slug=slug)
html = TemplateResponse(request, 'artist_page.html', context)
return HttpResponse(html.render())
def projects_page(request):
context = {}
context['artist'] = Artist.objects.all()
......
......@@ -77,3 +77,15 @@ footer > div {
line-height: 30px;
font-size: 20px;
}
.msg {
background-color: green;
display: inline-block;
padding: 10px;
color: white;
display: none;
}
.error {
background-color: red;
}
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
function print_message(target, msg_type, msg) {
var elem = document.querySelector(target);
var msg_field = elem.querySelector('.msg');
msg_field.textContent = msg;
msg_field.style.display = "inline-block";
if (msg_type == 'error') {
msg_field.classList.add('error');
} else {
msg_field.classList.remove('error');
}
}
var demo = new Vue({
el: '#app',
data: {
......@@ -16,31 +28,78 @@ var demo = new Vue({
name: this.artist.name.trim()
};
axios
.post('http://127.0.0.1:8000/api/artist/', newArtist);
.post('http://127.0.0.1:8000/api/artist/', newArtist)
.then(function(response){
print_message('.artist', 'success', 'Artist successfully added');
})
.catch(error => {
print_message('.artist', 'error', 'Error while adding artist, please report');
});
},
addProject: function () {
if (this.project.city) {
var city = this.project.city.trim();
} else {
var city = "";
};
var newProject = {
artist: this.artist.id,
name: this.project.name.trim(),
city: this.project.city.trim(),
city: city,
datefrom: this.project.datefrom,
dateto: this.project.dateto
};
axios
.post('http://127.0.0.1:8000/api/project/', newProject);
.post('http://127.0.0.1:8000/api/project/', newProject)
.then(function(response){
print_message('.project', 'success', 'Project successfully added');
})
.catch(error => {
print_message('.project', 'error', 'Error while adding project, please report');
});
},
addEntry: function () {
if (this.entry.description) {
var description = this.entry.description.trim();
} else {
var description = '';
};
if (this.entry.dimension) {
var dimension = this.entry.dimension.trim();
} else {
var dimension = '';
}
var newEntry = {
project: this.project.id,
signatory: this.entry.signatory.trim(),
description: this.entry.description.trim(),
dimension: this.entry.dimension.trim(),
description: description,
dimension: dimension,
visibility: this.entry.visibility,
type: this.entry.type
};
axios
.post('http://127.0.0.1:8000/api/entry/', newEntry);
.post('http://127.0.0.1:8000/api/entry/', newEntry)
.then(function(response){
print_message('.entry', 'success', 'Entry successfully added');
})
.catch(error => {
print_message('.entry', 'error', 'Error while adding entry, please report');
});
},
addMedia: function () {
const file = event.target.files[0]
axios.post('/add', file, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function(response){
print_message('.media', 'success', 'Media successfully uploaded');
})
.catch(error => {
print_message('.media', 'error', 'Error while uploading media, please report');
});
};
removeArtist: function (index) {
axios
.delete('http://127.0.0.1:8000/api/artist/'.concat(this.artist[index].id));
......@@ -62,7 +121,6 @@ var demo = new Vue({
{
switch (window.location.pathname) {
case "/artists/":
case "/add/":
axios
.get('http://127.0.0.1:8000/api/artist/')
.then(response => (this.artist = response.data));
......
......@@ -3,30 +3,43 @@
{% block jobs %}
<div class="main">
<h2>Create an artist</h2>
<form v-on:submit.prevent>
<form class="artist" v-on:submit.prevent='addArtist'>
<table>
{{ artist_form.as_table }}
</table>
<br>
<button type="submit" v-on:click="addArtist()">Submit</button>
<button type="submit">Submit</button>
<br><p class="msg"></p>
</form>
<h2>Create a project</h2>
<form v-on:submit.prevent>
<form class="project" v-on:submit.prevent='addProject'>
<table>
{{ project_form.as_table }}
</table>
<br>
<button type="submit" v-on:click="addProject()">Submit</button>
<button type='submit'>Submit</button>
<br><p class="msg"></p>
</form>
<h2>Add an entry</h2>
<form v-on:submit.preven>
<form class='entry' v-on:submit.prevent='addEntry'>
<table>
{{ entry_form.as_table }}
</table>
<br>
<button type="submit" v-on:click="addEntry()">Submit</button>
<button type="submit">Submit</button>
<br><p class="msg"></p>
</form>
<h2>Upload media</h2>
<form class='media' v-on:submit.prevent='addMedia'>
<table>
{{ media_form.as_table }}
</table>
<br>
<button type="submit">Submit</button>
<br><p class="msg"></p>
</form>
</div>
{% endblock %}
......@@ -7,7 +7,7 @@
<div v-for="(artist, index) in artist" class="artist">
<div class="col-sm-12">
<img src="https://uploads.wikiart.org/Content/images/ARTIST-480x600.jpg" width=100px>
<br><b><a :href="'/' + artist.slug">[[ artist.name ]]</a></b><br>
<br><b><a :href="'/en/' + artist.slug">[[ artist.name ]]</a></b><br>
<button class="btn" v-on:click="removeArtist([[ index ]])">Delete</button>
</div>
</div>
......
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