[chronojump-server] Now we can add images to the players. The photo of the players is composed with the timestamp to avo



commit c8655a77678ea9380d325f18bc4802b36cd6c1cc
Author: Marcos Venteo <mventeo gmail com>
Date:   Wed Jun 14 22:31:11 2017 +0200

    Now we can add images to the players. The photo of the players is composed with the timestamp to avoid 
cache problems of the browsers.

 chronojumpserver/__init__.py                       |    2 +-
 chronojumpserver/forms.py                          |    4 +-
 chronojumpserver/js/players.js                     |    4 +-
 .../static/images/photos/player_1_1497471778.jpg   |  Bin 0 -> 25133 bytes
 chronojumpserver/static/style.css                  |   51 +++++++++--------
 chronojumpserver/templates/_formhelpers.html       |   34 ++++++++---
 chronojumpserver/templates/layout.html             |   28 ++++++---
 chronojumpserver/templates/player_detail.html      |    2 +-
 chronojumpserver/views.py                          |   62 +++++++++++++++----
 9 files changed, 126 insertions(+), 61 deletions(-)
---
diff --git a/chronojumpserver/__init__.py b/chronojumpserver/__init__.py
index 8bb33fd..5ae3ba6 100755
--- a/chronojumpserver/__init__.py
+++ b/chronojumpserver/__init__.py
@@ -21,7 +21,7 @@ app.config['MYSQL_DATABASE_DB'] = config.get("db", "name")
 app.config['MYSQL_DATABASE_HOST'] = config.get("db", "server")
 app.config['CLUB_NAME'] = config.get("club", "name")
 app.secret_key = config.get("security", "secret_key")
-app.config['UPLOAD_FOLDER'] = "static/images"
+app.config['UPLOAD_FOLDER'] = "static/images/photos"
 
 
 @app.route('/js/<path:filename>')
diff --git a/chronojumpserver/forms.py b/chronojumpserver/forms.py
index 5e4ae78..9766cf1 100755
--- a/chronojumpserver/forms.py
+++ b/chronojumpserver/forms.py
@@ -7,8 +7,8 @@ from wtforms.validators import DataRequired, Length
 
 
 class PersonForm(FlaskForm):
-    fullname = StringField('Nom Complet', validators=[DataRequired()])
+    fullname = StringField('Nom Complet', validators=[DataRequired('El nom complet és 
obligatori!'.decode('utf-8'))])
     height=FloatField('Alçada'.decode('utf-8'), validators=[DataRequired()])
     weight=FloatField('Pes', [])
-    image=FileField('Image', validators=[FileRequired])
+    photo=FileField('Foto del Jugador')
     rfid = StringField('RFID', [validators.Length(max=23)])
diff --git a/chronojumpserver/js/players.js b/chronojumpserver/js/players.js
index 78c4d27..6be7a7f 100755
--- a/chronojumpserver/js/players.js
+++ b/chronojumpserver/js/players.js
@@ -67,8 +67,8 @@ $(document).ready(function() {
         data: 'imageName',
         orderable: false,
         render: function(value) {
-          var href = '/static/images/' + value;
-          var src = '/static/images/' + value;
+          var href = '/static/images/photos/' + value;
+          var src = '/static/images/photos/' + value;
           var html = '<a href="' + href + '" class="player-link"><img src="' + src + '" class="img-circle" 
height="60"></a>';
           return html;
         }
diff --git a/chronojumpserver/static/images/photos/player_1_1497471778.jpg 
b/chronojumpserver/static/images/photos/player_1_1497471778.jpg
new file mode 100644
index 0000000..b9e74dd
Binary files /dev/null and b/chronojumpserver/static/images/photos/player_1_1497471778.jpg differ
diff --git a/chronojumpserver/static/style.css b/chronojumpserver/static/style.css
index 1c3766a..1b00f92 100755
--- a/chronojumpserver/static/style.css
+++ b/chronojumpserver/static/style.css
@@ -2,51 +2,54 @@
     TODO: Some comment here Marcos
 */
 
+
 /* Stylesheet from chronojump home page */
+
 body {
-    font-family: "Source Sans Pro",HelveticaNeue-Light,"Helvetica Neue Light","Helvetica 
Neue",Helvetica,Arial,"Lucida Grande",sans-serif;
-    padding-bottom: 70px;
-    margin-top: 100px;
+  font-family: "Source Sans Pro", HelveticaNeue-Light, "Helvetica Neue Light", "Helvetica Neue", Helvetica, 
Arial, "Lucida Grande", sans-serif;
+  padding-bottom: 70px;
+  margin-top: 100px;
 }
 
 body.home {
-    margin-top: 0px;
+  margin-top: 0px;
 }
 
-
 .navbar-fixed-top {
-    background-color: #0f2351;
-    height: 80px;
+  background-color: #0f2351;
+  height: 80px;
+}
+
+.navbar-collapse {
+  background-color: #0f2351;
 }
 
 .header-index {
-    background-color: #0f2351;
-    height: 250px;
+  background-color: #0f2351;
+  height: 250px;
 }
 
 .header-index h1, .header-index h4 {
-    color: #fff;
-    font-weight: bold;
+  color: #fff;
+  font-weight: bold;
 }
 
-.navbar-fixed-top ul.nav > li > a{
-    padding-top: 30px;
-    color: #d5d9db;
-    font-weight: 600;
+.navbar-fixed-top ul.nav>li>a {
+  padding-top: 30px;
+  color: #d5d9db;
+  font-weight: 600;
 }
 
-.navbar-fixed-top ul.nav > li > a:hover{
-    color: #fff;
-    font-weight: 600;
+.navbar-fixed-top ul.nav>li>a:hover {
+  color: #fff;
+  font-weight: 600;
 }
 
-#main {
-
-}
+#main {}
 
 .footer {
-    background-color: #2b2b2b;
-    color: #ffffff;
+  background-color: #2b2b2b;
+  color: #ffffff;
 }
 
 .task-link {
@@ -54,5 +57,5 @@ body.home {
 }
 
 #results .colResult {
-    color: green;
+  color: green;
 }
diff --git a/chronojumpserver/templates/_formhelpers.html b/chronojumpserver/templates/_formhelpers.html
old mode 100644
new mode 100755
index 554b8b5..fb48425
--- a/chronojumpserver/templates/_formhelpers.html
+++ b/chronojumpserver/templates/_formhelpers.html
@@ -9,16 +9,32 @@
         <input class="form-control" type="text" value="{{field.data}}" name="{{field.name}}" 
id="{{field.name}}"/>
       {% elif field.type == "FileField" %}
         <div class="text-center">
-
-          <img class="img-rounded " src="/static/images/{{field.data}}">
-          <a id="btn_{{field.name}}" class="btn btn-default btn-block" 
onclick="selectFile_{{field.name}}(event)">Seleccionar foto</a>
-          <input class="hidden" type="file" name="{{field.name}}" id="{{field.name}}"/ />
+          {% if field.data %}
+          <img id="img_{{field.name}}" class="img-rounded " src="/static/images/photos/{{field.data}}">
+          {% else %}
+          <img id="img_{{field.name}}" class="img-rounded ">
+          {% endif %}
+          <a id="btn_{{field.name}}" class="btn btn-default btn-block">Seleccionar foto</a>
+          <input class="hidden" type="file" name="{{field.name}}" id="{{field.name}}" 
value="{{field.data}}"/>
           <script type="text/javascript">
-            function selectFile_{{field.name}}(e){
-                e.preventDefault();
-                document.getElementById('{{field.name}}').click();
-                console.log('File selected');
-            };
+              $('#btn_{{field.name}}').click(function(e) {
+                  e.preventDefault();
+                  $('#{{field.name}}').click();
+              });
+              /* Update the image and set the selected file for submit later */
+              $('#{{field.name}}').change(function(e) {
+                var _fileInput = this;
+
+                if (_fileInput.files && _fileInput.files.length > 0) {
+                    var reader = new FileReader();
+                    var _file = _fileInput.files[0];
+                    reader.onload = function (e) {
+                        $('#img_{{field.name}}').attr('src', e.target.result);
+                    }
+
+                    reader.readAsDataURL(_file);
+                 };
+              });
           </script>
         </div>
       {% endif %}
diff --git a/chronojumpserver/templates/layout.html b/chronojumpserver/templates/layout.html
index e17ebe2..f77959a 100755
--- a/chronojumpserver/templates/layout.html
+++ b/chronojumpserver/templates/layout.html
@@ -8,6 +8,8 @@
     <link rel="stylesheet" type="text/css" href="{{ url_for('assets', 
filename='font-awesome/css/font-awesome.min.css')}}" />
     <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css')}}" />
     {% endblock %}
+    <!-- Load jquery here to use in case of embedded javascript -->
+    <script src="{{ url_for('assets', filename='jquery/jquery-3.2.1.min.js')}}" /></script>
 </head>
 
 <body class="{% block body_class %}{% endblock %}">
@@ -15,18 +17,26 @@
     <nav class="navbar navbar-default navbar-fixed-top">
         <div class="container-fluid">
             <div class="navbar-header">
+              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" 
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
+                <span class="sr-only">Toggle navigation</span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+                <span class="icon-bar"></span>
+              </button>
                 <a class="navbar-brand" href="/">
                     <img alt="Brand" src="{{ url_for('static', filename='chronojump-logo.png')}}" 
height="60px">
                 </a>
             </div>
-            <ul class="nav navbar-nav navbar-right">
-                <li><a href="/">Inici</a></li>
-                <li><a href="/results">Resultats</a></li>
-                <li><a href="/player_list">Llistat Jugadors</a></li>
-                <li><a href="/player_add">Afegir Jugador</a></li>
-                <li><a href="#">RFID Perduda</a></li>
-                </li>
-            </ul>
+            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+              <ul class="nav navbar-nav navbar-right">
+                  <li><a href="/">Inici</a></li>
+                  <li><a href="/results">Resultats</a></li>
+                  <li><a href="/player_list">Llistat Jugadors</a></li>
+                  <li><a href="/player_add">Afegir Jugador</a></li>
+                  <li><a href="#">RFID Perduda</a></li>
+                  </li>
+              </ul>
+          </div>
         </div>
     </nav>
     {% endblock %}
@@ -43,7 +53,7 @@
     </nav>
     {% endblock %}
     {% block script %}
-    <script src="{{ url_for('assets', filename='jquery/jquery-3.2.1.min.js')}}" /></script>
+
     <script src="{{ url_for('assets', filename='bootstrap/js/bootstrap.min.js')}}" /></script>
     {% endblock %}
 </body>
diff --git a/chronojumpserver/templates/player_detail.html b/chronojumpserver/templates/player_detail.html
index f8f7100..bcbd582 100755
--- a/chronojumpserver/templates/player_detail.html
+++ b/chronojumpserver/templates/player_detail.html
@@ -9,7 +9,7 @@
     {{ form.csrf_token }}
     <div class="row">
         <div class="col-sm-4">
-          {{ render_field(form.image)}}
+          {{ render_field(form.photo)}}
         </div>
         <div class="col-sm-8">
           {{ render_field(form.fullname) }}
diff --git a/chronojumpserver/views.py b/chronojumpserver/views.py
index 3ea1b44..7fcc156 100755
--- a/chronojumpserver/views.py
+++ b/chronojumpserver/views.py
@@ -1,18 +1,19 @@
 # -*- coding: utf-8 -*-
-"""Chronojump Server views controller.
-
-"""
+"""Chronojump Server views controller."""
 from chronojumpserver import app
 from flask import render_template, request, redirect, url_for
+from flask_wtf.file import FileField
 from chronojumpserver.models import Person, Station
 from chronojumpserver.forms import PersonForm
 
 from chronojumpserver.database import db_session
-from werkzeug import secure_filename
+import os
+from time import time
 
 
 @app.route('/')
 def index():
+    """Chronojump Server Home page."""
     return render_template('index.html')
 
 
@@ -31,39 +32,74 @@ def show_players():
 @app.route('/player/<player_id>', methods=['GET', 'POST'])
 def player_detail(player_id):
     """Show players detail."""
+    has_errors = False
+    msg = ""
     # Get the player id passed by argument
     player = Person.query.filter(Person.id == player_id).first()
     form = PersonForm()
+
     if request.method == "GET":
 
         form.fullname.data = player.name
         form.height.data = player.height
         form.weight.data = player.weight
         form.rfid.data = player.rfid
-        form.image.data = player.imageName
+
     elif request.method == "POST":
+        # Save the image in photos folder
         if form.validate_on_submit():
-            # Update the player
+            """Form Valid. Update the player."""
+            # Check if a photo has been passed too
+            f = form.photo.data
+            # compose filename with id to avoid multiple images
+            if f:
+                # Update the photo too. First we'll erase the previous photo to
+                # assure there is only one photo of the player and to force the
+                # browser to load the photo beacause of the cache
+                if player.imageName:
+                    fullpath = os.path.join('chronojumpserver',
+                                            app.config['UPLOAD_FOLDER'],
+                                            player.imageName)
+                    # Remove if exists
+                    if os.path.exists(fullpath):
+                        os.unlink(fullpath)
+                # Set the new photo
+                new_photo = 'player_' + player_id + \
+                    '_' + str(int(time())) + '.jpg'
+                fullpath = os.path.join('chronojumpserver',
+                                        app.config['UPLOAD_FOLDER'],
+                                        new_photo)
+                # save the photo
+                f.save(fullpath)
+                player.imageName = new_photo
+            # Save the player
             db_session.query(Person).filter_by(id=player_id).update({
                 "name": form.fullname.data,
                 "height": form.height.data,
                 "weight": form.weight.data,
-                "rfid": form.rfid.data
+                "rfid": form.rfid.data,
+                "imageName": player.imageName
             })
             db_session.commit()
+            # Update done
+
+            msg = "S'han guardat correctament les dades"
         else:
-            print "Form is not valid!!!"
+            # There are some errors in the form
+            msg = 'Hi han hagut errors, revisa el formulari.'
+            has_errors = True
 
-    return render_template('player_detail.html', form=form)
+    form.photo.data = player.imageName
+    return render_template('player_detail.html', form=form, msg=msg,
+                           has_errors=has_errors)
 
 
 @app.route('/player/add', methods=['GET', 'POST'])
 def add_player():
-    """Show players detail."""
-    # Get the player id passed by argument
+    """Show form to add a new player."""
     form = PersonForm()
-    if request.method == "POST" and form.validate_on_submit():
-            # Update the player
+    if request.method == "POST":
+        """Form is valid, add the new player."""
         player = Person(
             name=form.fullname.data,
             height=form.height.data,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]