2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-15 19:45:46 +00:00

Support image uploads in the "notes" markdown fields

- Implemented using the existing EasyMDE library
- Copy / paste support
- Drag / drop support
This commit is contained in:
Oliver
2023-04-17 16:29:55 +10:00
parent 713aec1ae3
commit 779857b182
5 changed files with 115 additions and 9 deletions

View File

@ -21,8 +21,8 @@ from InvenTree.api import BulkDeleteMixin
from InvenTree.config import CONFIG_LOOKUPS
from InvenTree.filters import ORDER_FILTER, SEARCH_ORDER_FILTER
from InvenTree.helpers import inheritors
from InvenTree.mixins import (ListAPI, RetrieveAPI, RetrieveUpdateAPI,
RetrieveUpdateDestroyAPI)
from InvenTree.mixins import (ListAPI, ListCreateAPI, RetrieveAPI,
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI)
from InvenTree.permissions import IsSuperuser
from plugin.models import NotificationUserSetting
from plugin.serializers import NotificationUserSettingSerializer
@ -440,6 +440,20 @@ class ConfigDetail(RetrieveAPI):
return {key: value}
class NotesImageList(ListCreateAPI):
"""List view for all notes images."""
queryset = common.models.NotesImage.objects.all()
serializer_class = common.serializers.NotesImageSerializer
permission_classes = [permissions.IsAuthenticated, ]
def perform_create(self, serializer):
"""Create (upload) a new notes image"""
image = serializer.save()
image.user = self.request.user
image.save()
settings_api_urls = [
# User settings
re_path(r'^user/', include([
@ -473,6 +487,9 @@ common_api_urls = [
# Webhooks
path('webhook/<slug:endpoint>/', WebhookView.as_view(), name='api-webhook'),
# Uploaded images for notes
re_path(r'^notes-image-upload/', NotesImageList.as_view(), name='api-notes-image-list'),
# Currencies
re_path(r'^currency/', include([
re_path(r'^exchange/', CurrencyExchangeView.as_view(), name='api-currency-exchange'),

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.18 on 2023-04-17 05:54
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('common', '0016_alter_notificationentry_updated'),
]
operations = [
migrations.CreateModel(
name='NotesImage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('image', models.ImageField(help_text='Image file', upload_to='notes_images', verbose_name='Image')),
('date', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -2642,3 +2642,27 @@ class NewsFeedEntry(models.Model):
help_text=_('Was this news item read?'),
default=False
)
def rename_notes_image(instance, filename):
"""Function for renaming uploading image file. Will store in the 'notes' directory."""
fname = os.path.basename(filename)
return os.path.join('notes', fname)
class NotesImage(models.Model):
"""Model for storing uploading images for the 'notes' fields of various models.
Simply stores the image file, for use in the 'notes' field (of any models which support markdown)
"""
image = models.ImageField(
upload_to='notes_images',
verbose_name=_('Image'),
help_text=_('Image file'),
)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)

View File

@ -5,9 +5,10 @@ from django.urls import reverse
from rest_framework import serializers
from common.models import (InvenTreeSetting, InvenTreeUserSetting,
NewsFeedEntry, NotificationMessage)
NewsFeedEntry, NotesImage, NotificationMessage)
from InvenTree.helpers import construct_absolute_url, get_objectreference
from InvenTree.serializers import InvenTreeModelSerializer
from InvenTree.serializers import (InvenTreeAttachmentSerializerField,
InvenTreeModelSerializer)
class SettingsSerializer(InvenTreeModelSerializer):
@ -230,3 +231,25 @@ class ConfigSerializer(serializers.Serializer):
if not isinstance(instance, str):
instance = list(instance.keys())[0]
return {'key': instance, **self.instance[instance]}
class NotesImageSerializer(InvenTreeModelSerializer):
"""Serializer for the NotesImage model."""
class Meta:
"""Meta options for NotesImageSerializer."""
model = NotesImage
fields = [
'pk',
'image',
'user',
'date',
]
read_only_fields = [
'date',
'user',
]
image = InvenTreeAttachmentSerializerField(required=True)

View File

@ -380,6 +380,10 @@ function renderLink(text, url, options={}) {
}
/*
* Configure an EasyMDE editor for the given element,
* allowing markdown editing of the notes field.
*/
function setupNotesField(element, url, options={}) {
var editable = options.editable || false;
@ -419,12 +423,25 @@ function setupNotesField(element, url, options={}) {
element: document.getElementById(element),
initialValue: initial,
toolbar: toolbar_icons,
uploadImage: true,
imagePathAbsolute: true,
imageUploadFunction: function(imageFile, onSuccess, onError) {
// Attempt to upload the image to the InvenTree server
var form_data = new FormData();
form_data.append('image', imageFile);
inventreeFormDataUpload('{% url "api-notes-image-list" %}', form_data, {
success: function(response) {
console.log("Uploading image:", response.image);
onSuccess(response.image);
},
error: function(xhr, status, error) {
onError(error);
}
});
},
shortcuts: [],
renderingConfig: {
markedOptions: {
sanitize: true,
}
}
});