Image upload and display

master
Laurent 6 years ago
parent 261279b881
commit 759b23e6b1
  1. BIN
      db.sqlite3
  2. BIN
      news/__pycache__/choices.cpython-37.pyc
  3. BIN
      news/__pycache__/forms.cpython-37.pyc
  4. BIN
      news/__pycache__/models.cpython-37.pyc
  5. BIN
      news/__pycache__/urls.cpython-37.pyc
  6. BIN
      news/__pycache__/views.cpython-37.pyc
  7. 4
      news/choices.py
  8. 11
      news/forms.py
  9. 18
      news/migrations/0002_post_style.py
  10. BIN
      news/migrations/__pycache__/0002_post_style.cpython-37.pyc
  11. 6
      news/models.py
  12. BIN
      news/static/media/74d7e72e-e415-462e-8978-5ef942ff96a4
  13. BIN
      news/static/media/c0256a8f-14ff-473f-ae1c-2e7f7a83bb18
  14. BIN
      news/static/media/test.png
  15. BIN
      news/static/news/LibreBaskerville-Regular.otf
  16. 65
      news/static/news/css/app.css
  17. 3912
      news/static/news/css/foundation.css
  18. 1
      news/static/news/css/foundation.min.css
  19. 1
      news/static/news/js/app.js
  20. 219
      news/static/news/js/vendor/foundation.js
  21. 1
      news/static/news/js/vendor/foundation.min.js
  22. 10364
      news/static/news/js/vendor/jquery.js
  23. 480
      news/static/news/js/vendor/what-input.js
  24. 3
      news/static/news/style.css
  25. 48
      news/templates/base.html
  26. 73
      news/templates/news/index.html
  27. 7
      news/templates/news/post.html
  28. 21
      news/templates/news/submission.html
  29. 2
      news/urls.py
  30. 54
      news/views.py
  31. BIN
      pokercc/__pycache__/settings.cpython-37.pyc
  32. 2
      pokercc/settings.py

Binary file not shown.

@ -0,0 +1,4 @@
STYLE_CHOICES = (
(0, "Standard"),
(1, "Quote")
)

@ -0,0 +1,11 @@
from django import forms
from .choices import *
class PostForm(forms.Form):
title = forms.CharField(label='Title', max_length=200)
body = forms.CharField(label='Optional text', max_length=10000)
url = forms.CharField(label='URL', max_length=200)
# date = forms.DateTimeField('date published')
# state = forms.IntegerField(label='State', default=1)
style = forms.ChoiceField(label='Style',choices=STYLE_CHOICES, required=True)
image = forms.FileField()

@ -0,0 +1,18 @@
# Generated by Django 2.2.5 on 2019-09-11 14:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('news', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='post',
name='style',
field=models.IntegerField(default=0),
),
]

@ -15,12 +15,14 @@ class Post(models.Model):
url = models.CharField(max_length=200)
date = models.DateTimeField('date published')
state = models.IntegerField(default=0)
style = models.IntegerField(default=0)
image_url = models.CharField(max_length=100)
# state: posted, draft, waiting for submission
# image
def __str__(self):
return self.title
def top_comments(self):
return self.comment_set.all()[:3]
class Comment(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE, null=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

@ -0,0 +1,65 @@
@font-face {
font-family: LibreBaskerville;
src: url("LibreBaskerville-Regular.otf") format("opentype");
}
body {
background-color:#fff;
font-size:20px;
margin: 0px;
padding: 0px;
}
.content {
padding: 16px;
}
.content h1 {
font-family: 'LibreBaskerville';
font-size: 28px;
margin: 0px;
padding: 0px;
}
.post {
margin-bottom: 20px;
}
.comments {
color: #666;
padding: 0px 10px;
background-color: #efe;
border-radius: 16px;
}
.info {
text-align: right;
padding: 0px 20px;
margin-top: 10px;
font-size: 14px;
}
header {
/* width: 100%; */
text-align: center;
}
header a {
text-decoration: none;
color: #fff;
}
header h1 {
margin-bottom: 0;
}
header {
padding: 8px;
background-color: #333;
color: #fff;
/* font-size: 16px; */
}
li a {
color: red;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
$(document).foundation()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -0,0 +1,480 @@
/**
* what-input - A global utility for tracking the current input method (mouse, keyboard or touch).
* @version v5.1.2
* @link https://github.com/ten1seven/what-input
* @license MIT
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("whatInput", [], factory);
else if(typeof exports === 'object')
exports["whatInput"] = factory();
else
root["whatInput"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
'use strict';
module.exports = function () {
/*
* bail out if there is no document or window
* (i.e. in a node/non-DOM environment)
*
* Return a stubbed API instead
*/
if (typeof document === 'undefined' || typeof window === 'undefined') {
return {
// always return "initial" because no interaction will ever be detected
ask: function ask() {
return 'initial';
},
// always return null
element: function element() {
return null;
},
// no-op
ignoreKeys: function ignoreKeys() {},
// no-op
specificKeys: function specificKeys() {},
// no-op
registerOnChange: function registerOnChange() {},
// no-op
unRegisterOnChange: function unRegisterOnChange() {}
};
}
/*
* variables
*/
// cache document.documentElement
var docElem = document.documentElement;
// currently focused dom element
var currentElement = null;
// last used input type
var currentInput = 'initial';
// last used input intent
var currentIntent = currentInput;
// check for sessionStorage support
// then check for session variables and use if available
try {
if (window.sessionStorage.getItem('what-input')) {
currentInput = window.sessionStorage.getItem('what-input');
}
if (window.sessionStorage.getItem('what-intent')) {
currentIntent = window.sessionStorage.getItem('what-intent');
}
} catch (e) {}
// event buffer timer
var eventTimer = null;
// form input types
var formInputs = ['input', 'select', 'textarea'];
// empty array for holding callback functions
var functionList = [];
// list of modifier keys commonly used with the mouse and
// can be safely ignored to prevent false keyboard detection
var ignoreMap = [16, // shift
17, // control
18, // alt
91, // Windows key / left Apple cmd
93 // Windows menu / right Apple cmd
];
var specificMap = [];
// mapping of events to input types
var inputMap = {
keydown: 'keyboard',
keyup: 'keyboard',
mousedown: 'mouse',
mousemove: 'mouse',
MSPointerDown: 'pointer',
MSPointerMove: 'pointer',
pointerdown: 'pointer',
pointermove: 'pointer',
touchstart: 'touch'
// boolean: true if touch buffer is active
};var isBuffering = false;
// boolean: true if the page is being scrolled
var isScrolling = false;
// store current mouse position
var mousePos = {
x: null,
y: null
// map of IE 10 pointer events
};var pointerMap = {
2: 'touch',
3: 'touch', // treat pen like touch
4: 'mouse'
// check support for passive event listeners
};var supportsPassive = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function get() {
supportsPassive = true;
}
});
window.addEventListener('test', null, opts);
} catch (e) {}
/*
* set up
*/
var setUp = function setUp() {
// add correct mouse wheel event mapping to `inputMap`
inputMap[detectWheel()] = 'mouse';
addListeners();
doUpdate('input');
doUpdate('intent');
};
/*
* events
*/
var addListeners = function addListeners() {
// `pointermove`, `MSPointerMove`, `mousemove` and mouse wheel event binding
// can only demonstrate potential, but not actual, interaction
// and are treated separately
var options = supportsPassive ? { passive: true } : false;
// pointer events (mouse, pen, touch)
if (window.PointerEvent) {
window.addEventListener('pointerdown', setInput);
window.addEventListener('pointermove', setIntent);
} else if (window.MSPointerEvent) {
window.addEventListener('MSPointerDown', setInput);
window.addEventListener('MSPointerMove', setIntent);
} else {
// mouse events
window.addEventListener('mousedown', setInput);
window.addEventListener('mousemove', setIntent);
// touch events
if ('ontouchstart' in window) {
window.addEventListener('touchstart', eventBuffer, options);
window.addEventListener('touchend', setInput);
}
}
// mouse wheel
window.addEventListener(detectWheel(), setIntent, options);
// keyboard events
window.addEventListener('keydown', eventBuffer);
window.addEventListener('keyup', eventBuffer);
// focus events
window.addEventListener('focusin', setElement);
window.addEventListener('focusout', clearElement);
};
// checks conditions before updating new input
var setInput = function setInput(event) {
// only execute if the event buffer timer isn't running
if (!isBuffering) {
var eventKey = event.which;
var value = inputMap[event.type];
if (value === 'pointer') {
value = pointerType(event);
}
var ignoreMatch = !specificMap.length && ignoreMap.indexOf(eventKey) === -1;
var specificMatch = specificMap.length && specificMap.indexOf(eventKey) !== -1;
var shouldUpdate = value === 'keyboard' && eventKey && (ignoreMatch || specificMatch) || value === 'mouse' || value === 'touch';
if (currentInput !== value && shouldUpdate) {
currentInput = value;
try {
window.sessionStorage.setItem('what-input', currentInput);
} catch (e) {}
doUpdate('input');
}
if (currentIntent !== value && shouldUpdate) {
// preserve intent for keyboard typing in form fields
var activeElem = document.activeElement;
var notFormInput = activeElem && activeElem.nodeName && formInputs.indexOf(activeElem.nodeName.toLowerCase()) === -1;
if (notFormInput) {
currentIntent = value;
try {
window.sessionStorage.setItem('what-intent', currentIntent);
} catch (e) {}
doUpdate('intent');
}
}
}
};
// updates the doc and `inputTypes` array with new input
var doUpdate = function doUpdate(which) {
docElem.setAttribute('data-what' + which, which === 'input' ? currentInput : currentIntent);
fireFunctions(which);
};
// updates input intent for `mousemove` and `pointermove`
var setIntent = function setIntent(event) {
// test to see if `mousemove` happened relative to the screen to detect scrolling versus mousemove
detectScrolling(event);
// only execute if the event buffer timer isn't running
// or scrolling isn't happening
if (!isBuffering && !isScrolling) {
var value = inputMap[event.type];
if (value === 'pointer') {
value = pointerType(event);
}
if (currentIntent !== value) {
currentIntent = value;
try {
window.sessionStorage.setItem('what-intent', currentIntent);
} catch (e) {}
doUpdate('intent');
}
}
};
var setElement = function setElement(event) {
if (!event.target.nodeName) {
// If nodeName is undefined, clear the element
// This can happen if click inside an <svg> element.
clearElement();
return;
}
currentElement = event.target.nodeName.toLowerCase();
docElem.setAttribute('data-whatelement', currentElement);
if (event.target.classList && event.target.classList.length) {
docElem.setAttribute('data-whatclasses', event.target.classList.toString().replace(' ', ','));
}
};
var clearElement = function clearElement() {
currentElement = null;
docElem.removeAttribute('data-whatelement');
docElem.removeAttribute('data-whatclasses');
};
// buffers events that frequently also fire mouse events
var eventBuffer = function eventBuffer(event) {
// set the current input
setInput(event);
// clear the timer if it happens to be running
window.clearTimeout(eventTimer);
// set the isBuffering to `true`
isBuffering = true;
// run the timer
eventTimer = window.setTimeout(function () {
// if the timer runs out, set isBuffering back to `false`
isBuffering = false;
}, 100);
};
/*
* utilities
*/
var pointerType = function pointerType(event) {
if (typeof event.pointerType === 'number') {
return pointerMap[event.pointerType];
} else {
// treat pen like touch
return event.pointerType === 'pen' ? 'touch' : event.pointerType;
}
};
// detect version of mouse wheel event to use
// via https://developer.mozilla.org/en-US/docs/Web/Events/wheel
var detectWheel = function detectWheel() {
var wheelType = void 0;
// Modern browsers support "wheel"
if ('onwheel' in document.createElement('div')) {
wheelType = 'wheel';
} else {
// Webkit and IE support at least "mousewheel"
// or assume that remaining browsers are older Firefox
wheelType = document.onmousewheel !== undefined ? 'mousewheel' : 'DOMMouseScroll';
}
return wheelType;
};
// runs callback functions
var fireFunctions = function fireFunctions(type) {
for (var i = 0, len = functionList.length; i < len; i++) {
if (functionList[i].type === type) {
functionList[i].fn.call(undefined, type === 'input' ? currentInput : currentIntent);
}
}
};
// finds matching element in an object
var objPos = function objPos(match) {
for (var i = 0, len = functionList.length; i < len; i++) {
if (functionList[i].fn === match) {
return i;
}
}
};
var detectScrolling = function detectScrolling(event) {
if (mousePos['x'] !== event.screenX || mousePos['y'] !== event.screenY) {
isScrolling = false;
mousePos['x'] = event.screenX;
mousePos['y'] = event.screenY;
} else {
isScrolling = true;
}
};
/*
* init
*/
// don't start script unless browser cuts the mustard
// (also passes if polyfills are used)
if ('addEventListener' in window && Array.prototype.indexOf) {
setUp();
}
/*
* api
*/
return {
// returns string: the current input type
// opt: 'intent'|'input'
// 'input' (default): returns the same value as the `data-whatinput` attribute
// 'intent': includes `data-whatintent` value if it's different than `data-whatinput`
ask: function ask(opt) {
return opt === 'intent' ? currentIntent : currentInput;
},
// returns string: the currently focused element or null
element: function element() {
return currentElement;
},
// overwrites ignored keys with provided array
ignoreKeys: function ignoreKeys(arr) {
ignoreMap = arr;
},
// overwrites specific char keys to update on
specificKeys: function specificKeys(arr) {
specificMap = arr;
},
// attach functions to input and intent "events"
// funct: function to fire on change
// eventType: 'input'|'intent'
registerOnChange: function registerOnChange(fn, eventType) {
functionList.push({
fn: fn,
type: eventType || 'input'
});
},
unRegisterOnChange: function unRegisterOnChange(fn) {
var position = objPos(fn);
if (position || position === 0) {
functionList.splice(position, 1);
}
}
};
}();
/***/ })
/******/ ])
});
;

@ -1,3 +0,0 @@
li a {
color: red;
}

@ -4,30 +4,36 @@
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="{% static 'news/style.css' %}">
<title>{% block title %}My amazing site{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% static 'news/css/app.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'news/css/foundation.min.css' %}">
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
<body>
<h1><a href="{% url 'news:index' %}">Poker CC</a></h1>
<p>
{% if user.is_authenticated %}
<a href="{% url 'news:submission' %}">Submit</a>
{% else %}
<a href="{% url 'news:createaccount' %}">Create account</a>
{% endif %}
</p>
<hr/>
<div id="content">
{% block content %}{% endblock %}
</div>
<hr/>
<footer>
some footer
</footer>
<!-- Header -->
<header>
<h1><a href="{% url 'news:index' %}">Poker CC</a></h1>
<p>
{% if user.is_authenticated %}
<a href="{% url 'news:submission' %}">Submit</a>
{% else %}
<a href="{% url 'news:createaccount' %}">Create account</a>
{% endif %}
</p>
</header>
<!-- Body -->
<div class="content">
{% block content %}{% endblock %}
</div>
<!-- Footer -->
<footer>
<!-- some footer -->
</footer>
</body>
</html>

@ -1,14 +1,81 @@
{% extends "base.html" %}
{% load static %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% if latest_post_list %}
<ul>
{% for post in latest_post_list %}
<li><a href="{{ post.url }}">{{ post.title }}</a> - <a href="{% url 'news:post' post.id %}">comments</a></li>
<!-- A post -->
{% if post.style == 0 %}
<div class="grid-x post">
<div class="cell large-2 large-offset-2 info">
<br/>
{{ post.date }}
<br/>
{{ post.author.username }}
<br/>
<a href="{% url 'news:post' post.id %}">comments</a>
</div>
<div class="cell large-4">
<div class="grid-y">
<div class="cell large-4">
<img src="{% static 'media/' %}{{ post.image_url }}"/>
<h1><a href="{{ post.url }}">{{ post.title }}</a></h1>
{{ post.body }}
</div>
<div class="cell large-4 comments">
<!-- Some comments -->
{% for comment in post.top_comments %}
<div class="grid-x">
<div class="cell small-2 large-2">{{ comment.body }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% else %}
<div class="grid-x post">
<div class="cell large-2 large-offset-2 info">
<img src="{% static 'media/' %}{{ post.image_url }}" width="100" height="100"/>
<br/>
{{ post.date }}
<br/>
{{ post.author.username }}
<br/>
<a href="{% url 'news:post' post.id %}">comments</a>
</div>
<div class="cell large-4">
<div class="grid-y">
<div class="cell large-4">
<h1><a href="{{ post.url }}">{{ post.title }}</a></h1>
{{ post.body }}
</div>
<div class="cell large-4 comments">
<!-- Some comments -->
{% for comment in post.top_comments %}
<div class="grid-x">
<div class="cell small-2 large-2">{{ comment.body }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</ul>
{% else %}
<p>No posts are available.</p>
{% endif %}

@ -1,10 +1,15 @@
{% extends "base.html" %}
{% load static %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
<img src="{% static 'media/' %}{{ post.image_url }}"/>
<a href="{{ post.url }}"><h1>{{ post.title }}</h1></a>
<h3>written by {{ post.author.username }}</h3>
<p>submitted by {{ post.author.username }}</p>
<p>----Body----</p>
<p>{{ post.content }}</p>
<p>----Comments----</p>

@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block title %}My amazing submission{% endblock %}
{% block content %}
@ -11,26 +11,27 @@
<h1>Submit some amazing content!</h1>
<form action="{% url 'news:submit' %}" method="post">
<form action="{% url 'news:submission' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<!--
<p>
<span>Title</span>>
<span>Title</span>
<input type="text" name="title" maxlength="200" required id="id_title" size="100">
</p>
<p>
<span>URL</span>>
<span>URL</span>
<input type="text" name="url" maxlength="200" required id="id_url" size="100">
</p>
<p>
<span>Body</span>>
<input type="text" name="body" maxlength="10000" required id="id_body" size="100">
<span>Optional text</span>
<textarea name="body" rows="8" cols="80">
</p>
<p>
<span>Image URL</span>>
<input type="text" name="image_url" maxlength="200" required id="id_image_url" size="100">
<span>Image URL</span>
<input type="file" name="image_file" id="image_file"/>
</p>
<p>
@ -42,7 +43,7 @@
<label for="choice3">Program</label>
</p>
<br/>
<br/> -->
<input type="submit" value="Submit">
</form>

@ -7,7 +7,7 @@ urlpatterns = [
path('', views.index, name='index'),
path('<int:post_id>', views.post, name='post'),
path('submission', views.submission, name='submission'),
path('submit', views.submit, name='submit'),
# path('submit', views.submit, name='submit'),
path('<int:post_id>/comment', views.comment, name='comment'),
path('submitted', views.submitted, name='submitted'),
path('createaccount', views.createaccount, name='createaccount'),

@ -3,13 +3,15 @@ from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.template import loader
from django.urls import reverse
from .models import Post, Comment
from .forms import PostForm
from datetime import datetime
import logging
from django.conf import settings
import uuid
# Create your views here.
def index(request):
latest_post_list = Post.objects.filter(state=1).order_by('-date')[:10]
latest_post_list = Post.objects.filter(state=1).order_by('-date')[:25]
context = { 'latest_post_list' : latest_post_list }
return render(request, 'news/index.html', context)
@ -17,26 +19,48 @@ def post(request, post_id):
post = get_object_or_404(Post, pk=post_id)
return render(request, 'news/post.html', {'post': post})
def submission(request):
return render(request, 'news/submission.html', {})
# def submission(request):
# return render(request, 'news/submission.html', {})
def createaccount(request):
return render(request, 'news/createaccount.html', {})
def submit(request):
def submission(request):
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = Post.objects.create(author=request.user,date=datetime.today())
post.title = form.cleaned_data['title']
post.body = form.cleaned_data['body']
post.url = form.cleaned_data['url']
if 'state' in request.POST:
post = Post.objects.create(author=request.user,date=datetime.today())
post.title = request.POST['title']
post.body = request.POST['body']
post.url = request.POST['url']
post.image_url = request.POST['image_url']
post.state = request.POST['state']
post.save()
filename = str(uuid.uuid4())
handle_uploaded_file(filename, request.FILES['image'])
post.image_url = filename
post.state = 1
post.save()
return HttpResponseRedirect(reverse('news:submitted'))
# if a GET (or any other method) we'll create a blank form
else:
raise Http404("You must select a publication type")
form = PostForm()
return render(request, 'news/submission.html', {'form': form})
# title = forms.CharField(label='Title', max_length=200)
# body = forms.CharField(label='Optional text', max_length=10000)
# url = forms.CharField(label='URL', max_length=200)
# # date = forms.DateTimeField('date published')
# # state = forms.IntegerField(label='State', default=1)
# image = forms.FileField()
return HttpResponseRedirect(reverse('news:submitted'))
def handle_uploaded_file(filename, f):
with open(settings.MEDIA_ROOT + filename, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
def submitted(request):
return render(request, 'news/submitted.html', {})

@ -15,6 +15,8 @@ import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'news/static/media/')
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/

Loading…
Cancel
Save