How to send file from Mayan EDMS to external api? - python

I'm still learning Django and there is still a lot of unknown to me.
The problem is that I can't pull the .pdf (or any other format) to be sent by ajax post method to external API. So on the reciving side I only get the string location of the file not the actual file.
I have put the following javascript code in the generic_list_items_subtemplate.html
{% load i18n %}
{% load static %}
{% load common_tags %}
{% load navigation_tags %}
<div class="row">
<div class="col-xs-12">
<h4>
{% if page_obj %}
{% if page_obj.paginator.num_pages != 1 %}
{% blocktrans with page_obj.start_index as start and page_obj.end_index as end and page_obj.paginator.object_list|length as total and page_obj.number as page_number and page_obj.paginator.num_pages as total_pages %}Total ({{ start }} - {{ end }} out of {{ total }}) (Page {{ page_number }} of {{ total_pages }}){% endblocktrans %}
{% else %}
{% blocktrans with page_obj.paginator.object_list|length as total %}Total: {{ total }}{% endblocktrans %}
{% endif %}
{% else %}
{% blocktrans with object_list|length as total %}Total: {{ total }}{% endblocktrans %}
{% endif %}
</h4>
<hr>
<div class="well center-block">
<div class="clearfix">
<div class="pull-right">
<form action="{% url 'common:multi_object_action_view' %}" class="form-multi-object-action" method="get">
{% if object_list %}
{% if not hide_multi_item_actions %}
{% get_multi_item_links_form object_list %}
{% endif %}
{% if multi_item_actions %}
<fieldset style="margin-top: -10px;">
<input class="check-all" type="checkbox"/>
{{ multi_item_form }}
</fieldset>
{% endif %}
{% endif %}
</form>
</div>
</div>
{% if object_list %}
<hr style="border-bottom: 1px solid lightgrey;">
{% endif %}
<div class="row row-items">
{% for object in object_list %}
<div class="{{ column_class|default:'col-xs-12 col-sm-4 col-md-3 col-lg-2' }}">
<div class="panel panel-primary panel-item">
<div class="panel-heading">
<div class="form-group" id="myform">
<div class="checkbox">
<label for="id_indexes_0">
{% if multi_item_actions %}
{% if multi_select_item_properties %}
<input class="form-multi-object-action-checkbox check-all-slave checkbox" type="checkbox" name="properties_{{ object|get_encoded_parameter:multi_select_item_properties }}" />
{% else %}
<input class="form-multi-object-action-checkbox check-all-slave checkbox" type="checkbox" name="{{ object.get_absolute_url }}" />
{% endif %}
{% endif %}
<span style="color: white; word-break: break-all; overflow-wrap: break-word;">
{% if not hide_object %}
{% if main_object %}
{% with object|object_property:main_object as object %}
{% if not hide_link %}<a name="test" href="{{ object.get_absolute_url }}">{{ object }}</a>{% else %}{{ object }}{% endif %}
{% endwith %}
{% else %}
{% if not hide_link %}{{ object }}{% else %}{{ object }}{% endif %}
{% endif %}
{% endif %}
</span>
</label>
</div>
</div>
</div>
<div class="panel-body">
{% if not hide_columns %}
{% for column in object|get_source_columns %}
<div class="text-center" style="">{% source_column_resolve column=column %}{{ column_result }}</div>
{% endfor %}
{% endif %}
{% for column in extra_columns %}
<div class="text-center"><span class="list-extra-column-label">{{ column.name }}</span>: {{ object|object_property:column.attribute }}</div>
{% endfor %}
{% if not hide_links %}
<p class="text-center">
{% get_menu_links 'object menu' source=object as resolved_links %}
{% for object_navigation_links in resolved_links %}
{% with 'true' as as_dropdown %}
{% include 'navigation/generic_navigation.html' %}
{% endwith %}
{% endfor %}
</p>
{% endif %}
</div>
</div>
</div>
{% empty %}
<div class="col-xs-12">
{% include 'appearance/no_results.html' %}
</div>
{% endfor %}
</div>
<!--</form>-->
{% include 'pagination/pagination.html' %}
</div>
</div>
</div>
<!--{% if object_list %}-->
<form method="post">
{% csrf_token %}
<input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajD1cn">
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-3">
<button id="sendBTN" class="btn btn-success" type="submit">Send checked documents to another database</button>
</div>
<div class="col-md-3"></div>
</div>
</form>
<br>
<br>
<br>
<!--{% endif %}-->
<script type="text/javascript">
'use strict';
var $data = [];
$(document).on("click", "input[type='checkbox']", (e) => {
var name = $(e.target).attr("name");
if($(e.target).prop("checked")){
$data.push(name);
}else{
$data = jQuery.grep($data, function(value) {
return value != name;
});
}
console.log($data);
});
function csrfSafeMethod(method)
{
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if(!csrfSafeMethod(settings.type) && !this.crossDomain)
{
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
document.getElementById("sendBTN").onclick = function() {
var form_data = new FormData();
// form_data.append('file', $('#myform').get(0));
form_data.append('file', $data);
console.log(form_data);
$.ajax({
type: "POST",
// contentType: "application/x-www-form-urlencoded",
contentType : false,
processData: false,
url: "http://192.168.10.22:5000/api/FileRecive/GetDocument",
dataType: "json",
data: form_data,
success: function (data) {
data = $.parseJSON(data);
alert("success");
},
error: function (xhr) {
alert("error - " + xhr.statusText);
}
});
};
$(function() {
$('.row-items > [class*="col"] .panel-item .panel-heading').matchHeight();
$('.row-items > [class*="col"] .panel-item .panel-body').matchHeight();
$('.row-items > [class*="col"] .panel-item').matchHeight();
});
</script>
On the reciving side I am getting
name = "file"
value = "/documents/12/preview/"
But I want to get the file not this string. I have no idea how to target file to send it dirrectly.

The URL "/documents/12/preview/" is the URL to view the document using the user interface. If what you want is the actual file of the document, you need to use Mayan's API. Since documents in Mayan are a collection of versions, you need the ID of the latest version of the document you want. For this the API URL for the document detail which is:
"/api/documents/271/"
This will give you something like this:
From there look up the dictionary key "latest_version" and then the key "download_url". The download URL in the screenshot is "http://127.0.0.1:8000/api/documents/271/versions/267/download/". Do a GET request to this URL and you get the actual file of the document. Save the file in temporary variable (or Javascript Blob file object https://developer.mozilla.org/en-US/docs/Web/API/Blob) and then send it to your custom API with a POST request.
Another option is to just send the "download_url" to your API and have a worker process fetch the document data, that way you don't have to store the binary data of the document in the browsers memory.
For more information about Mayan's API go to "Tools" -> "API Documentation" and you'll get an API documentation view that allows testing the API with the live data in your installation.

Related

Django 'endfor', expected 'endblock'

I am attempting to learn Django but keep receiving the error " 'endfor', expected 'endblock'. Did you forget to register or load this tag? " when I add the {% for key,value in
price.DISPLAY.items %} {{ key }} {% endfor %} part of the code. How can I fix this? Any help would be great thanks.
home.html
{% extends 'base.html' %} {% block content %} {% for key,value in
price.DISPLAY.items %} {{ key }} {% endfor %}
<br />
<br />
{{ price.DISPLAY }}
<div class="jumbotron">
<h1 class="display-4">Welcome</h1>
</div>
<div class="container">
<div class="row">
{% for info in api.Data %}
<div class="card" style="width: 18rem">
<img src="{{info.imageurl}}" class="card-img-top" alt="{{info.source}}" />
<div class="card-body">
<h5 class="card-title">{{info.title}}</h5>
<p class="card-text">{{info.body}}</p>
<a href="{{info.url}}" class="btn btn-secondary" target="_blank"
>Read more</a
>
</div>
</div>
{% endfor %}
</div>
</div>
{{ api.Data }} {% endblock content %}
A template tag should not span multiple lines. You should write the {% for … %} tag on a single line:
{% extends 'base.html' %} {% block content %}
{% for key,value in price.DISPLAY.items %} {{ key }} {% endfor %}
…
{% endblock content %}

Javascript ID not showing reference to input text box - Django

{% extends 'halls/base.html' %}
{% block content %}
<div class="container">
<h2>Add Video to {{hall.title}}</h2>
<form method="post">
{% csrf_token %}
{% load widget_tweaks %}
{% for field in form %}
<div class="form-group {% if field.errors %} alert alert-danger {% endif %}">
{{ field.errors }}
{{ field.label_tag }}
{% render_field field class='form-control' %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary"> Add</button>
</form>
<br>
<h2>OR</h2>
<form>
{% for field in search_form %}
<div class="form-group ">
{{ field.errors }}
{{ field.label_tag }}
{% render_field field class='form-control' %}
</div>
{% endfor %}
</form>
<div id="search_results"></div>
<script type="text/javascript">
var delayTimer;
$("#id_search_term").keyup(function (){
clearTimeout(delayTimer);
$('#search_results').text('Loadingggg');
});
</script>
</div>
{% endblock %}
this is the HTML code. SO basically the whole idea here is when I inspect the search_form, it should give the id of the input box as "id_search_term". But when I inspect the box, it gives as id="id_search".
I am not able to find a way to reference the input box with the ID in the script tag

Displaying a message as a popup/alert in Django?

I have a form that, upon submission it just redirects to itself again. I'm trying to display a message that says "You have entered (work_area)." Currently, I only got the displaying part without the variable in it, but it shows within the html after the user submits it. I would like it to be a popup or alert message that the user can close after they see it, but I don't understand how this would work in Django.
views.py
class EnterExitArea(CreateView):
model = EmployeeWorkAreaLog
template_name = "operations/enter_exit_area.html"
form_class = WarehouseForm
#success_message = "You have logged into %(work_area)s"
def form_valid(self, form):
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
if 'enter_area' in self.request.POST:
form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(station_number=station)).update(time_in=datetime.now())
messages.info(self.request, "You have entered")
return HttpResponseRedirect(self.request.path_info)
enter_exit_area.html
{% extends "base.html" %}
{% block main %}
<form id="warehouseForm" action="" method="POST" class="form-horizontal" novalidate >
{% csrf_token %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<div>
<div>
<label>Employee</label>
{{ form.employee_number }}
</div>
<div>
<label>Work Area</label>
{{ form.work_area }}
</div>
<div>
<label>Station</label>
{{ form.station_number }}
</div>
</div>
<div>
<div>
<button type="submit" name="enter_area" value="Enter">Enter Area</button>
</div>
</div>
</form>
{% endblock main %}
And it displays like this:
Edit:
This is more a javascript question but anyways, this is how I handle this (if you are using bootstrap):
1) Create a message.html file with the following content:
{% for message in messages %}
<div class="toast notification bg-{% if message.tags == 'error' %}danger{% else %}{{message.tags}}{% endif %}" role="alert" aria-live="assertive" aria-atomic="true" data-delay="5000">
<div class="toast-header">
<strong class="mr-auto">
{% if message.tags == 'error' %}
<i class="fas fa-times mr-2"></i>
{% elif message.tags == 'warning' %}
<i class="fas fa-exclamation mr-2"></i>
{% elif message.tags == 'info' %}
<i class="fas fa-info mr-2"></i>
{% elif message.tags == 'success' %}
<i class="fas fa-check mr-2"></i>
{% endif %}
{{message.tags|capfirst}}
</strong>
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="toast-body">
{{message|safe}}
</div>
</div>
{% endfor %}
2) Change your base.html and add:
...
{% include 'message.html' %}
...
<!-- and at the end:-->
<script src="{% static 'js/jquery-3.4.1.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
{% if messages %}
<script>
{% for message in messages %}
$(document).ready(function () {
$('.toast').toast('show');
});
{% endfor %}
</script>
{% endif %}
Also, don't forget to include bootstrap.
This way you can use django messages on all of your templates, without explicitly change them.
Edit
You also need this custom css class in order for your notification to show on top right of the page:
.notification{
position: absolute;
top: 5rem;
right: 1rem;
}
Django has built-in functions for that which is messages.
messages.success(self.request,"message sent")
In your HTML, make sure to create a message class.
{% if message.tags %} class="{{message.tags}}"{% endif %}

Change BooleanField from False to True when message is opened

I've created my own message engine on Django framework to let users send messages to each others, here is my message model
models.py
class Message(models.Model):
sender = models.ForeignKey(UserModel, related_name="sender", on_delete='CASCADE')
receiver = models.ForeignKey(UserModel, related_name="receiver", on_delete='CASCADE')
msg_title = models.CharField(max_length=150, verbose_name='عنوان الرسالة', default='رسالة جديدة من مستخدم فوستانيا')
msg_content = models.TextField(max_length=1200,verbose_name='محتوى الرسالة')
created_at = models.DateTimeField(auto_now=True)
read = models.BooleanField(default=False)
Then am listing messages for the user, they can see the messages with read=False as a new message, they are able to click it to see the full message, I want the read status to be changed to True after the user clicks the message from the template,, How to do it!
urls.py
path('messages/', views.messages, name="messages"),
path('messages/<int:pk>/', views.message_page, name="message_page"),
views.py
#login_required
def messages(request):
inbox = Message.objects.filter(receiver=request.user, read=True)
context = {
'inbox': inbox,
}
return render(request, 'fostania_web_app/messages.html', context)
def message_page(request, pk):
current_msg = get_object_or_404(Message, pk=pk)
context = {
'current_msg': current_msg,
}
return render(request, 'fostania_web_app/message_page.html', context)
Message list template message.html
{% extends 'fostania_web_app/base.html' %}
{% block content %}
{% load static %}
{% if user.is_authenticated %}
<br><br>
<div class="card text-white bg-warning mb-3" style="max-width: 75rem;" align="right">
<div class="card-header">رسائل جديدة </div>
<div class="card-body">
<p class="card-text">
{% if new_messages.count != 0 %}
{% for msg in new_messages %}
<img src="{% static 'img/new-msg.png' %}"> {{ msg.msg_title }}
<br>
{% endfor %}
{% else %}
لا توجد رسائل غير مقروءة
{% endif %}
</p>
</div>
</div>
<!-- old msgs -->
<div class="card text-dark bg-ligh mb-3" style="max-width: 75rem;" align="right">
<div class="card-header"><img src="{% static 'img/inbox.png' %}"> صندوق الوارد </div>
<div class="card-body">
<p class="card-text">
{% for msg in inbox %}
<img src="{% static 'img/old-msg.png' %}"> {{ msg.msg_title }}<br>
{% endfor %}
</p>
</div>
</div>
{% else %}
يتوجب عليك تسجيل الدخول اولاً
{% endif %}
{% endblock %}
Message body after clicking and passing it's pk message_page.html
{% extends 'fostania_web_app/base.html' %}
{% block content %}
{% load static %}
<Br><br>
<div class="card bg-light mb-3" style="max-width: 50rem;" align="right ">
<div class="card-header">{{ current_msg.sender.name }}</div>
<div class="card-body">
<h5 class="card-title">{{ current_msg.msg_title }}</h5>
<p class="card-text">{{ current_msg.msg_content }}
<Br><br>
<button class="btn btn-success">إرسـال رد</button>
<button class="btn btn-danger">رجوع للرسائل </button>
</p>
</div>
</div>
{% endblock %}
You can avoid too much work by simply updating the message being read:
def message_page(request, pk):
current_msg = get_object_or_404(Message, pk=pk)
current_msg.read = True
current_msg.save()
context = {
'current_msg': current_msg,
}
return render(request, 'fostania_web_app/message_page.html', context)
BONUS:
instead of
{% if new_messages.count != 0 %}
{% for msg in new_messages %}
''' '''
{% endfor %}
{% else %}
لا توجد رسائل غير مقروءة
{% endif %}
Inside the loop, you can check whether the msg is read or not rather than send one more queryset, so you can simply do
{% for msg in new_messages %} # instead of new_messages, send all_messages
{% if msg.read %}
''' old message '''
{% else %}
''' new message '''
{% endif %}
{% empty %}
لا توجد رسائل غير مقروءة # don't really know what does that mean
{% endfor %}

How do I hide or show content for each iteration?

I have a Lecture model which contains lectures. For each lecture I have a title and a content and eventually some files. I was trying to make that when somebody presses on a title, the title and the content will display under, but only for that lecture. Problem is that if I use a class, all lectures will be shown and if I use and id only the first one will be shown. How should I do this ?
$('#title').click(function () {
$('#lecture-hide').toggle();
});
{% for c in category.list %}
<div id="title">
<p>Lecture {{ forloop.counter }}: <span>{{ c.lecture_title }}</span>
</p>
<br>
</div>
<div id="lecture-hide" style="display: none;">
<br>
<li><h5>{{ c.lecture_title }}</h5></li>
<li><p>{{ c.content }}</p></li>
{% for file in c.files.all %}
{% if file.files %}
{% if forloop.first %}
<p id="files">Lecture files:</p>
{% endif %}
<li><a class="media"
href='{{ MEDIA_URL }}{{ file.files.url }}'><i
class="fas fa-download"></i>{{ file.files.name }}</a></li>
{% endif %}
{% endfor %}
<br>
</div>
{% endfor %}
Maybe you can use next selector in your jQuery code like this:
$('div.title').click(function () {
$(this).next().toggle();
});
You have to change id of the title to class to apply this to every element of the list.
You need to set dynamic attributes in your html:
{% for c in category.list %}
<div class="title" id="title-{{ c.id }}">
<!-- the content -->
</div>
<div class="lecture-hide" for="title-{{ c.id }}" style="display: none;">
<!-- the content -->
</div>
{% endfor %}
and in JQuery
$('.title').click(function () {
$('.lecture-hide[for="title-' + $(this).attr('id') + '"]').toggle();
});
This will works even if the html elements order change.

Categories