mirror of
https://github.com/partitioncloud/partitioncloud-server.git
synced 2025-01-23 17:26:26 +01:00
Add the ability to attach files to a partition
This commit is contained in:
parent
971d54af41
commit
f8670f4901
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ partitioncloud/partitions
|
|||||||
partitioncloud/search-partitions
|
partitioncloud/search-partitions
|
||||||
partitioncloud/static/thumbnails
|
partitioncloud/static/thumbnails
|
||||||
partitioncloud/static/search-thumbnails
|
partitioncloud/static/search-thumbnails
|
||||||
|
partitioncloud/attachments
|
||||||
|
1
make.sh
1
make.sh
@ -3,6 +3,7 @@
|
|||||||
init () {
|
init () {
|
||||||
mkdir -p "instance"
|
mkdir -p "instance"
|
||||||
mkdir -p "partitioncloud/partitions"
|
mkdir -p "partitioncloud/partitions"
|
||||||
|
mkdir -p "partitioncloud/attachments"
|
||||||
mkdir -p "partitioncloud/search-partitions"
|
mkdir -p "partitioncloud/search-partitions"
|
||||||
mkdir -p "partitioncloud/static/thumbnails"
|
mkdir -p "partitioncloud/static/thumbnails"
|
||||||
mkdir -p "partitioncloud/static/search-thumbnails"
|
mkdir -p "partitioncloud/static/search-thumbnails"
|
||||||
|
@ -65,10 +65,14 @@ class Album():
|
|||||||
db = get_db()
|
db = get_db()
|
||||||
return db.execute(
|
return db.execute(
|
||||||
"""
|
"""
|
||||||
SELECT partition.uuid, partition.name, partition.author, partition.user_id FROM partition
|
SELECT p.uuid, p.name, p.author, p.user_id,
|
||||||
JOIN contient_partition ON partition_uuid = partition.uuid
|
CASE WHEN MAX(a.uuid) IS NOT NULL THEN 1 ELSE 0 END AS has_attachment
|
||||||
|
FROM partition AS p
|
||||||
|
JOIN contient_partition ON contient_partition.partition_uuid = p.uuid
|
||||||
JOIN album ON album.id = album_id
|
JOIN album ON album.id = album_id
|
||||||
|
LEFT JOIN attachments AS a ON p.uuid = a.partition_uuid
|
||||||
WHERE album.uuid = ?
|
WHERE album.uuid = ?
|
||||||
|
GROUP BY p.uuid, p.name, p.author, p.user_id
|
||||||
""",
|
""",
|
||||||
(self.uuid,),
|
(self.uuid,),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
33
partitioncloud/modules/classes/attachment.py
Normal file
33
partitioncloud/modules/classes/attachment.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
from ..db import get_db
|
||||||
|
|
||||||
|
|
||||||
|
class Attachment():
|
||||||
|
def __init__(self, uuid=None, data=None):
|
||||||
|
db = get_db()
|
||||||
|
if uuid is not None:
|
||||||
|
self.uuid = uuid
|
||||||
|
data = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT * FROM attachments
|
||||||
|
WHERE uuid = ?
|
||||||
|
""",
|
||||||
|
(self.uuid,)
|
||||||
|
).fetchone()
|
||||||
|
if data is None:
|
||||||
|
raise LookupError
|
||||||
|
|
||||||
|
elif data is not None:
|
||||||
|
self.uuid = data["uuid"]
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise LookupError
|
||||||
|
|
||||||
|
self.name = data["name"]
|
||||||
|
self.user_id = data["user_id"]
|
||||||
|
self.filetype = data["filetype"]
|
||||||
|
self.partition_uuid = data["partition_uuid"]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.name}.{self.filetype}"
|
@ -3,6 +3,7 @@ from flask import current_app
|
|||||||
|
|
||||||
from ..db import get_db
|
from ..db import get_db
|
||||||
from .user import User
|
from .user import User
|
||||||
|
from .attachment import Attachment
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ class Partition():
|
|||||||
self.body = data["body"]
|
self.body = data["body"]
|
||||||
self.user_id = data["user_id"]
|
self.user_id = data["user_id"]
|
||||||
self.source = data["source"]
|
self.source = data["source"]
|
||||||
|
self.attachments = None
|
||||||
else:
|
else:
|
||||||
raise LookupError
|
raise LookupError
|
||||||
|
|
||||||
@ -95,3 +97,15 @@ class Partition():
|
|||||||
""",
|
""",
|
||||||
(self.uuid,),
|
(self.uuid,),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
|
||||||
|
def load_attachments(self):
|
||||||
|
db = get_db()
|
||||||
|
if self.attachments is None:
|
||||||
|
data = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT * FROM attachments
|
||||||
|
WHERE partition_uuid = ?
|
||||||
|
""",
|
||||||
|
(self.uuid,)
|
||||||
|
)
|
||||||
|
self.attachments = [Attachment(data=i) for i in data]
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
Partition module
|
Partition module
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
from uuid import uuid4
|
||||||
from flask import Blueprint, abort, send_file, render_template, request, redirect, flash, session
|
from flask import Blueprint, abort, send_file, render_template, request, redirect, flash, session
|
||||||
|
|
||||||
from .db import get_db
|
from .db import get_db
|
||||||
from .auth import login_required, admin_required
|
from .auth import login_required, admin_required
|
||||||
from .utils import get_all_partitions, User, Partition
|
from .utils import get_all_partitions, User, Partition, Attachment
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint("partition", __name__, url_prefix="/partition")
|
bp = Blueprint("partition", __name__, url_prefix="/partition")
|
||||||
@ -15,21 +16,110 @@ bp = Blueprint("partition", __name__, url_prefix="/partition")
|
|||||||
@bp.route("/<uuid>")
|
@bp.route("/<uuid>")
|
||||||
def partition(uuid):
|
def partition(uuid):
|
||||||
db = get_db()
|
db = get_db()
|
||||||
partition = db.execute(
|
try:
|
||||||
"""
|
partition = Partition(uuid=uuid)
|
||||||
SELECT * FROM partition
|
except LookupError:
|
||||||
WHERE uuid = ?
|
|
||||||
""",
|
|
||||||
(uuid,)
|
|
||||||
).fetchone()
|
|
||||||
|
|
||||||
if partition is None:
|
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
return send_file(
|
return send_file(
|
||||||
os.path.join("partitions", f"{uuid}.pdf"),
|
os.path.join("partitions", f"{uuid}.pdf"),
|
||||||
download_name = f"{partition['name']}.pdf"
|
download_name = f"{partition.name}.pdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@bp.route("/<uuid>/attachments")
|
||||||
|
def attachments(uuid):
|
||||||
|
db = get_db()
|
||||||
|
try:
|
||||||
|
partition = Partition(uuid=uuid)
|
||||||
|
except LookupError:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
partition.load_attachments()
|
||||||
|
return render_template(
|
||||||
|
"partition/attachments.html",
|
||||||
|
partition=partition,
|
||||||
|
user=User(user_id=session.get("user_id"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/<uuid>/add-attachment", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def add_attachment(uuid):
|
||||||
|
db = get_db()
|
||||||
|
try:
|
||||||
|
partition = Partition(uuid=uuid)
|
||||||
|
except LookupError:
|
||||||
|
abort(404)
|
||||||
|
user = User(user_id=session.get("user_id"))
|
||||||
|
|
||||||
|
if user.id != partition.user_id and user.access_level != 1:
|
||||||
|
flash("Cette partition ne vous appartient pas")
|
||||||
|
return redirect(request.referrer)
|
||||||
|
|
||||||
|
error = None # À mettre au propre
|
||||||
|
if "file" not in request.files:
|
||||||
|
error = "Aucun fichier n'a été fourni."
|
||||||
|
else:
|
||||||
|
if "name" not in request.form or request.form["name"] == "":
|
||||||
|
name = ".".join(request.files["file"].filename.split(".")[:-1])
|
||||||
|
else:
|
||||||
|
name = request.form["name"]
|
||||||
|
|
||||||
|
if name == "":
|
||||||
|
error = "Pas de nom de fichier"
|
||||||
|
|
||||||
|
else:
|
||||||
|
filename = request.files["file"].filename
|
||||||
|
ext = filename.split(".")[-1]
|
||||||
|
if ext not in ["mid", "mp3"]:
|
||||||
|
error = "Extension de fichier non supportée"
|
||||||
|
|
||||||
|
if error is not None:
|
||||||
|
flash(error)
|
||||||
|
return redirect(request.referrer)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
attachment_uuid = str(uuid4())
|
||||||
|
|
||||||
|
db.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO attachments (uuid, name, filetype, partition_uuid, user_id)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
""",
|
||||||
|
(attachment_uuid, name, ext, partition.uuid, user.id),
|
||||||
|
)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
file = request.files["file"]
|
||||||
|
file.save(f"partitioncloud/attachments/{attachment_uuid}.{ext}")
|
||||||
|
break
|
||||||
|
|
||||||
|
except db.IntegrityError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
return redirect(f"/partition/{partition.uuid}/attachments")
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/attachment/<uuid>.<filetype>")
|
||||||
|
def attachment(uuid, filetype):
|
||||||
|
db = get_db()
|
||||||
|
try:
|
||||||
|
attachment = Attachment(uuid=uuid)
|
||||||
|
except LookupError:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
assert filetype == attachment.filetype
|
||||||
|
|
||||||
|
return send_file(
|
||||||
|
os.path.join("attachments", f"{uuid}.{attachment.filetype}"),
|
||||||
|
download_name = f"{attachment.name}.{attachment.filetype}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<uuid>/edit", methods=["GET", "POST"])
|
@bp.route("/<uuid>/edit", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def edit(uuid):
|
def edit(uuid):
|
||||||
|
@ -7,13 +7,20 @@ from .classes.user import User
|
|||||||
from .classes.album import Album
|
from .classes.album import Album
|
||||||
from .classes.groupe import Groupe
|
from .classes.groupe import Groupe
|
||||||
from .classes.partition import Partition
|
from .classes.partition import Partition
|
||||||
|
from .classes.attachment import Attachment
|
||||||
|
|
||||||
|
|
||||||
def get_all_partitions():
|
def get_all_partitions():
|
||||||
db = get_db()
|
db = get_db()
|
||||||
partitions = db.execute(
|
partitions = db.execute(
|
||||||
"""
|
"""
|
||||||
SELECT * FROM partition
|
SELECT p.uuid, p.name, p.author, p.body, p.user_id,
|
||||||
|
CASE WHEN MAX(a.uuid) IS NOT NULL THEN 1 ELSE 0 END AS has_attachment
|
||||||
|
FROM partition AS p
|
||||||
|
JOIN contient_partition ON contient_partition.partition_uuid = p.uuid
|
||||||
|
JOIN album ON album.id = album_id
|
||||||
|
LEFT JOIN attachments AS a ON p.uuid = a.partition_uuid
|
||||||
|
GROUP BY p.uuid, p.name, p.author, p.user_id
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
# Transform sql object to dictionary usable in any thread
|
# Transform sql object to dictionary usable in any thread
|
||||||
@ -23,7 +30,8 @@ def get_all_partitions():
|
|||||||
"name": p["name"],
|
"name": p["name"],
|
||||||
"author": p["author"],
|
"author": p["author"],
|
||||||
"body": p["body"],
|
"body": p["body"],
|
||||||
"user_id": p["user_id"]
|
"user_id": p["user_id"],
|
||||||
|
"has_attachment": p["has_attachment"]
|
||||||
} for p in partitions
|
} for p in partitions
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ DROP TABLE IF EXISTS search_results;
|
|||||||
DROP TABLE IF EXISTS groupe;
|
DROP TABLE IF EXISTS groupe;
|
||||||
DROP TABLE IF EXISTS groupe_contient_user;
|
DROP TABLE IF EXISTS groupe_contient_user;
|
||||||
DROP TABLE IF EXISTS groupe_contient_album;
|
DROP TABLE IF EXISTS groupe_contient_album;
|
||||||
|
DROP TABLE IF EXISTS attachments;
|
||||||
|
|
||||||
CREATE TABLE user (
|
CREATE TABLE user (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -66,3 +67,11 @@ CREATE TABLE groupe_contient_album (
|
|||||||
album_id INTEGER NOT NULL,
|
album_id INTEGER NOT NULL,
|
||||||
PRIMARY KEY (groupe_id, album_id)
|
PRIMARY KEY (groupe_id, album_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE attachments (
|
||||||
|
uuid TEXT(36) PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
filetype TEXT NOT NULL DEFAULT 'mp3',
|
||||||
|
partition_uuid INTEGER NOT NULL,
|
||||||
|
user_id INTEGER NOT NULL
|
||||||
|
);
|
@ -342,13 +342,18 @@ img.partition-thumbnail {
|
|||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-button {
|
.partition-action {
|
||||||
float: right;
|
padding: 7px;
|
||||||
transform: translateX(-96%) translateY(-162%);
|
margin: 3px;
|
||||||
padding: 2%;
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.2);
|
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.2);
|
||||||
background-color: var(--color-blue);
|
background-color: #cdd6f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partition-buttons {
|
||||||
|
float: right;
|
||||||
|
display: flex;
|
||||||
|
transform: translateX(-22px) translateY(-115px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -705,3 +710,43 @@ td {
|
|||||||
.x-scrollable {
|
.x-scrollable {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Attachment page */
|
||||||
|
#pdf-embed {
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
width: -moz-available;
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
width: stretch;
|
||||||
|
|
||||||
|
height: 50vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
midi-visualizer {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
midi-player {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments > table {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments > table > tbody > tr > td {
|
||||||
|
border: none;
|
||||||
|
min-width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
@ -18,7 +18,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="/partition/{{ partition['uuid'] }}/details"><div class="edit-button">🔍</div></a>
|
<div class="partition-buttons">
|
||||||
|
{% if partition["has_attachment"] %}
|
||||||
|
<a href="/partition/{{ partition['uuid'] }}/attachments"><div class="partition-action">📎</div></a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="/partition/{{ partition['uuid'] }}/details"><div class="edit-button partition-action">🔍</div></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<input name="name" type="text" required="" placeholder="Titre"><br/>
|
<input name="name" type="text" required="" placeholder="Titre"><br/>
|
||||||
<input name="author" type="text" placeholder="Auteur"><br/>
|
<input name="author" type="text" placeholder="Auteur"><br/>
|
||||||
<textarea id="paroles" name="body" type="text" placeholder="Paroles"></textarea><br/>
|
<textarea id="paroles" name="body" type="text" placeholder="Paroles"></textarea><br/>
|
||||||
<input name="file" type="file" required=""><br/>
|
<input name="file" type="file" accept=".pdf" required=""><br/>
|
||||||
<input type="submit" value="Ajouter">
|
<input type="submit" value="Ajouter">
|
||||||
</form>
|
</form>
|
||||||
<a href="#!" class="close-dialog">Close</a>
|
<a href="#!" class="close-dialog">Close</a>
|
||||||
@ -75,9 +75,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{% if partition["user_id"] == g.user.id or g.user.access_level == 1 %}
|
<div class="partition-buttons">
|
||||||
<a href="/partition/{{ partition['uuid'] }}/edit"><div class="edit-button">✏️</div></a>
|
{% if partition["has_attachment"] %}
|
||||||
|
<a href="/partition/{{ partition['uuid'] }}/attachments"><div class="partition-action">📎</div></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if partition["user_id"] == g.user.id or g.user.access_level == 1 %}
|
||||||
|
<a href="/partition/{{ partition['uuid'] }}/edit"><div class="partition-action">✏️</div></a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
|
@ -17,6 +17,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
<div class="partition-buttons">
|
||||||
|
{% if partition["has_attachment"] %}
|
||||||
|
<a href="/partition/{{ partition['uuid'] }}/attachments"><div class="partition-action">📎</div></a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<form action="/albums/add-partition" class="add-partition-form" method="post">
|
<form action="/albums/add-partition" class="add-partition-form" method="post">
|
||||||
<select name="album-uuid">
|
<select name="album-uuid">
|
||||||
{% for album in user.albums %}
|
{% for album in user.albums %}
|
||||||
|
@ -170,9 +170,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content-container">
|
<div id="content-container">
|
||||||
|
{% if not DISABLE_HEADER %}
|
||||||
<header id="page-header">
|
<header id="page-header">
|
||||||
<h1>PartitionCloud</h1>
|
<h1>PartitionCloud</h1>
|
||||||
</header>
|
</header>
|
||||||
|
{% endif %}
|
||||||
{% for message in get_flashed_messages() %}
|
{% for message in get_flashed_messages() %}
|
||||||
<div class="flash">{{ message }}</div>
|
<div class="flash">{{ message }}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
63
partitioncloud/templates/partition/attachments.html
Normal file
63
partitioncloud/templates/partition/attachments.html
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{% set DISABLE_HEADER=true %}
|
||||||
|
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Attachments de {{ partition.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block dialogs %}
|
||||||
|
<dialog id="create-attachment">
|
||||||
|
<h2>Ajouter un attachment à {{ partition.name }}</h2>
|
||||||
|
<form action="/partition/{{ partition.uuid }}/add-attachment" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="text" name="name" id="name" placeholder="Nom"><br/>
|
||||||
|
<input name="file" type="file" accept=".mp3,.mid" required=""><br/>
|
||||||
|
<input type="submit" value="Ajouter">
|
||||||
|
</form>
|
||||||
|
<a href="#!" class="close-dialog">Close</a>
|
||||||
|
</dialog>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<object id="pdf-embed" width="400" height="500" type="application/pdf" data="/partition/{{ partition.uuid }}">
|
||||||
|
<p>
|
||||||
|
Impossible d'afficher le pdf dans ce navigateur.
|
||||||
|
Il est conseillé d'utiliser Firefox sur Android.
|
||||||
|
</p>
|
||||||
|
</object>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/combine/npm/tone@14.7.58,npm/@magenta/music@1.23.1/es6/core.js,npm/focus-visible@5,npm/html-midi-player@1.5.0"></script>
|
||||||
|
<midi-visualizer type="staff" id="midi-visualizer"></midi-visualizer>
|
||||||
|
|
||||||
|
|
||||||
|
{% if partition.attachments | length > 0 %}
|
||||||
|
<div id="attachments">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{% for attachment in partition.attachments %}
|
||||||
|
<tr>
|
||||||
|
{% if attachment.filetype == "mp3" %}
|
||||||
|
<td><audio controls src="/partition/attachment/{{ attachment.uuid }}.mp3"></td>
|
||||||
|
<td>🎙️ {{ attachment.name }}</td>
|
||||||
|
{% elif attachment.filetype == "mid" %}
|
||||||
|
|
||||||
|
<td><midi-player
|
||||||
|
src="/partition/attachment/{{ attachment.uuid }}.mid"
|
||||||
|
sound-font visualizer="#midi-visualizer" data-js-focus-visible>
|
||||||
|
</midi-player>
|
||||||
|
<noscript>MIDI support needs JavaScript</noscript>
|
||||||
|
</td>
|
||||||
|
<td>🎵 {{ attachment.name }}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
{% if user %}
|
||||||
|
<div class="centered">
|
||||||
|
<a href="#create-attachment"><button>Ajouter un attachment</button></a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -64,6 +64,17 @@
|
|||||||
<td>Paroles</td>
|
<td>Paroles</td>
|
||||||
<td><textarea id="paroles" name="body" type="text" placeholder="Paroles">{{ partition.body }}</textarea><br/></td>
|
<td><textarea id="paroles" name="body" type="text" placeholder="Paroles">{{ partition.body }}</textarea><br/></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Pièces jointes</td>
|
||||||
|
{% set _ = partition.load_attachments() %}
|
||||||
|
<td><a href="/partition/{{ partition.uuid }}/attachments">
|
||||||
|
{% if partition.attachments %}
|
||||||
|
Oui, {{ partition.attachments | length }}
|
||||||
|
{% else %}
|
||||||
|
En rajouter
|
||||||
|
{% endif %}
|
||||||
|
</a></td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" value="Mettre à jour" />
|
<input type="submit" value="Mettre à jour" />
|
||||||
|
@ -35,6 +35,17 @@
|
|||||||
<td>Paroles</td>
|
<td>Paroles</td>
|
||||||
<td><textarea id="paroles" name="body" type="text" placeholder="Paroles">{{ partition.body }}</textarea><br/></td>
|
<td><textarea id="paroles" name="body" type="text" placeholder="Paroles">{{ partition.body }}</textarea><br/></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Pièces jointes</td>
|
||||||
|
{% set _ = partition.load_attachments() %}
|
||||||
|
<td><a href="/partition/{{ partition.uuid }}/attachments">
|
||||||
|
{% if partition.attachments %}
|
||||||
|
Oui, {{ partition.attachments | length }}
|
||||||
|
{% else %}
|
||||||
|
En rajouter
|
||||||
|
{% endif %}
|
||||||
|
</a></td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" value="Mettre à jour" />
|
<input type="submit" value="Mettre à jour" />
|
||||||
|
Loading…
Reference in New Issue
Block a user