Skip to content

Commit df1c12c

Browse files
committed
Library:
Jam.py now uses SQLAlchemy connection poll when image field read_only attribute is set user can not change the image by double-clicking on it Some bugs fixed Documentation: How to lock a record so that users cannot edit it at the same time topic added
1 parent 57770bd commit df1c12c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+48862
-136
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ dist/
77
build/
88
docs/_build/
99
*.xml
10+
*.lock
1011
/admin/
1112
/jam_docs/
1213
/css/
@@ -28,5 +29,4 @@ doc/_build/
2829
os
2930
jam*.zip
3031
wsgi.conf
31-
langs.lock
3232
xchanges.txt

demo/js/demo.js

+77-1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ function Events1() { // demo
147147
}
148148

149149
function on_edit_form_created(item) {
150+
151+
task.lock_record(item);
152+
150153
item.edit_options.inputs_container_class = 'edit-body';
151154
item.edit_options.detail_container_class = 'edit-detail';
152155

@@ -278,6 +281,65 @@ function Events1() { // demo
278281
item.view_form.find("#report-btn").hide();
279282
}
280283
}
284+
285+
function lock_record(item, repeated) {
286+
if (!item.master && item.is_edited() && task.user_info.user_id) {
287+
var item = item,
288+
locks = task.record_locks.copy(),
289+
on_before_apply = item.on_before_apply,
290+
on_edit_form_closed = item.on_edit_form_closed;
291+
292+
locks.set_where({item_id: item.ID, item_rec_id: item.id.value});
293+
locks.open();
294+
if (locks.rec_count) {
295+
locks.edit()
296+
}
297+
else {
298+
locks.append();
299+
}
300+
locks.item_id.value = item.ID;
301+
locks.item_rec_id.value = item.id.value;
302+
locks.user_id.value = task.user_info.user_id;
303+
locks.user_name.value = task.user_info.user_name;
304+
locks.lock_date.value = new Date();
305+
locks.post();
306+
locks.apply();
307+
308+
if (!repeated) {
309+
item.on_before_apply = function(locked_item) {
310+
var mess;
311+
locks.set_where({item_id: locked_item.ID, item_rec_id: locked_item.id.value});
312+
locks.open();
313+
if (locks.user_id.value !== task.user_info.user_id) {
314+
mess = 'Saving is prohibited. The record is edited by the user ' +
315+
locks.user_name.value + '.'
316+
item.question(mess + ' Continue editing?',
317+
function() {
318+
locked_item._applying = false;
319+
if (!locked_item.is_edited()) {
320+
locked_item.edit();
321+
}
322+
lock_record(locked_item, true);
323+
},
324+
function() {
325+
item.cancel_edit();
326+
}
327+
);
328+
throw mess;
329+
}
330+
};
331+
332+
item.on_edit_form_closed = function(locked_item) {
333+
if (on_before_apply) {
334+
locked_item.on_before_apply = on_before_apply;
335+
}
336+
if (on_edit_form_closed) {
337+
on_edit_form_closed(locked_item);
338+
}
339+
}
340+
};
341+
}
342+
}
281343
this.on_page_loaded = on_page_loaded;
282344
this.on_view_form_created = on_view_form_created;
283345
this.on_view_form_shown = on_view_form_shown;
@@ -290,6 +352,7 @@ function Events1() { // demo
290352
this.on_view_form_keyup = on_view_form_keyup;
291353
this.on_edit_form_keyup = on_edit_form_keyup;
292354
this.create_print_btns = create_print_btns;
355+
this.lock_record = lock_record;
293356
}
294357

295358
task.events.events1 = new Events1();
@@ -321,9 +384,16 @@ function Events10() { // demo.catalogs.customers
321384
task.customers_report.customers.value = item.selections;
322385
task.customers_report.print(false);
323386
}
387+
388+
function on_edit_form_created(item) {
389+
if (task.user_info.user_id === 1) {
390+
item.photo.read_only = false;
391+
}
392+
}
324393
this.on_view_form_created = on_view_form_created;
325394
this.send_email = send_email;
326395
this.print = print;
396+
this.on_edit_form_created = on_edit_form_created;
327397
}
328398

329399
task.events.events10 = new Events10();
@@ -466,7 +536,6 @@ function Events16() { // demo.journals.invoices
466536
});
467537
}
468538

469-
470539
// function on_edit_form_created(item) {
471540
// item.read_only = item.id.value % 2 === 1;
472541
// }
@@ -505,11 +574,18 @@ function Events16() { // demo.journals.invoices
505574
// // item.view_form.find("#edit-btn").prop("disabled", !item.view_options.can_edit);
506575
// }
507576
// }
577+
578+
579+
580+
function on_before_apply(item) {
581+
582+
}
508583
this.on_field_get_text = on_field_get_text;
509584
this.on_field_get_html = on_field_get_html;
510585
this.on_field_changed = on_field_changed;
511586
this.on_detail_changed = on_detail_changed;
512587
this.on_before_post = on_before_post;
588+
this.on_before_apply = on_before_apply;
513589
}
514590

515591
task.events.events16 = new Events16();

docs/contents.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Jam.py documentation contents
33
=============================
44

5-
.. toctree::
5+
.. toctree::
66
:hidden:
77

88
index

docs/how to/export_import_csv_files.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ corresponding functions when you click on them:
2828
}
2929

3030
function csv_import(item) {
31-
task.upload('static/files', {callback: function(file_name) {
31+
task.upload('static/files', {accept: '.csv', callback: function(file_name) {
3232
item.server('import_scv', [file_name], function(error) {
3333
if (error) {
3434
item.warning(error);

docs/how to/how_to_deploy_project_on_pythonanywhere.txt

-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ How to deploy project on PythonAnywhere
66
:doc:`Project parameters </admin/project/parameters>`
77
to ``false``.
88

9-
You can do this later in the Application Builder after deployment.
10-
In this case, you must restart the server.
11-
129
* Use pip to install Jam.py. To do this, open the bash console and run the
1310
following command (for Python 3.7):
1411

docs/how to/how_to_lock_record.txt

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
==================================================================
2+
How to lock a record so that users cannot edit it at the same time
3+
==================================================================
4+
5+
To implement the lock that described in this topic create ``record_locks`` item
6+
with the following fields:
7+
8+
* item_id - INTEGER
9+
* item_rec_id - INTEGER
10+
* user_id - INTEGER
11+
* user_name - TEXT
12+
13+
Below is the ``lock_record`` function that when executed in the
14+
``on_edit_form_created`` event handler checks if record is being edited (not is new) and
15+
then looks for the record in the ``record_locks`` table with the same item
16+
:doc:`ID </refs/client/abstr_item/at_id>`
17+
and the value of the primary key field of the record:
18+
19+
.. code-block:: js
20+
21+
locks.set_where({item_id: item.ID, item_rec_id: item.id.value});
22+
23+
if such record exists it changes it, otherwise adds a new record,
24+
and sets the the following values to its fields:
25+
26+
* item_id value is :doc:`ID </refs/client/abstr_item/at_id>` of the item that is edited,
27+
* item_rec_id - value of the primary key field of the record,
28+
* user_id - ID of the user (see :doc:`Roles </admin/roles>`),
29+
* user_name - name of the user
30+
31+
This function also overrides the ``on_before_apply`` event of the item, so that
32+
it looks for the record with current user ID and record id and checks whether
33+
user_id field value is equals this user ID and if it is not gives a warning that
34+
saving is prohibited, the record is being edited by another user.
35+
36+
The ``on_edit_form_closed`` event handler of the item is also overriden to
37+
return event handlers to the previous state.
38+
39+
If this code is placed to item client module these checks will be performed only
40+
for this item. To make these checks for all items place this code to the task
41+
client module.
42+
43+
.. code-block:: js
44+
45+
function on_edit_form_created(item) {
46+
task.lock_record(item);
47+
// some other code
48+
}
49+
50+
function lock_record(item, repeated) {
51+
if (!item.master && item.is_edited() && task.user_info.user_id) {
52+
var item = item,
53+
locks = task.record_locks.copy(),
54+
on_before_apply = item.on_before_apply,
55+
on_edit_form_closed = item.on_edit_form_closed;
56+
57+
locks.set_where({item_id: item.ID, item_rec_id: item.id.value});
58+
locks.open();
59+
if (locks.rec_count) {
60+
locks.edit()
61+
}
62+
else {
63+
locks.append();
64+
}
65+
locks.item_id.value = item.ID;
66+
locks.item_rec_id.value = item.id.value;
67+
locks.user_id.value = task.user_info.user_id;
68+
locks.user_name.value = task.user_info.user_name;
69+
locks.lock_date.value = new Date();
70+
locks.post();
71+
locks.apply();
72+
73+
if (!repeated) {
74+
item.on_before_apply = function(locked_item) {
75+
var mess;
76+
locks.set_where({item_id: locked_item.ID, item_rec_id: locked_item.id.value});
77+
locks.open();
78+
if (locks.rec_count && locks.user_id.value !== task.user_info.user_id) {
79+
mess = 'Saving is prohibited. The record is being edited by the user ' +
80+
locks.user_name.value + '.'
81+
item.question(mess + ' Continue editing?',
82+
function() {
83+
if (!locked_item.is_edited()) {
84+
locked_item.edit();
85+
}
86+
lock_record(locked_item, true);
87+
},
88+
function() {
89+
item.cancel_edit();
90+
}
91+
);
92+
throw mess;
93+
}
94+
if (on_before_apply) {
95+
on_before_apply(locked_item)
96+
}
97+
};
98+
99+
item.on_edit_form_closed = function(locked_item) {
100+
if (on_edit_form_closed) {
101+
on_edit_form_closed(locked_item);
102+
}
103+
locked_item.on_edit_form_closed = on_edit_form_closed;
104+
locked_item.on_before_apply = on_before_apply;
105+
}
106+
};
107+
}
108+
}

docs/how to/index.txt

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Here is a useful code that you can use in your applications:
1212
how_to_execute_script_from_client
1313
to_append_a_record_without_view_form
1414
export_import_csv_files
15+
how_to_lock_record
1516
how_to_deploy_project_on_pythonanywhere

docs/programming/interface/form_events.txt

+26-7
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,22 @@ Form events
33
===========
44

55
After the form is created, and the form's html template have been added to the
6-
DOM, the application triggers the following events (prefix is the type of the form):
6+
DOM, the application triggers the following events for view forms:
77

8-
* on_prefix_form_created - the event is triggered when the form has been created but not shown yet
8+
* ``on_view_form_created`` - the event is triggered when the form has been created but not shown yet
99

10-
* on_prefix_form_shown -the event is triggered when the the form has been shown
10+
* ``on_view_form_shown`` -the event is triggered when the the form has been shown
1111

12-
* on_prefix_form_close_query - the event is triggered when an attempt is made to close the form
12+
* ``on_view_form_close_query`` - the event is triggered when an attempt is made to close the form
1313

14-
* on_prefix_form_closed - the event is triggered when the form has been closed
14+
* ``on_view_form_closed`` - the event is triggered when the form has been closed
1515

16-
* on_prefix_form_keydown - the event is triggered when the keydown event occurs for the form
16+
* ``on_view_form_keydown`` - the event is triggered when the keydown event occurs for the form
1717

18-
* on_prefix_form_keyup - the event is triggered when the keyup event occurs for the form
18+
* ``on_view_form_keyup`` - the event is triggered when the keyup event occurs for the form
19+
20+
For other form types - edit, filter and param, replace 'view' on the form type, for example
21+
``on_edit_form_created`` for edit form.
1922

2023
These events are processed by the ``_process_event`` in th *jam.js* module.
2124
Below we explain how it works.
@@ -61,6 +64,22 @@ Below we explain how it works.
6164
}
6265
}
6366

67+
Let's start with close query event
68+
69+
Close query event
70+
=================
71+
72+
This event is triggered when an attempt is made to close the form.
73+
74+
We will look at this event using the edit form as an example.
75+
76+
If the ``on_edit_form_close_query`` event handler is defined in the item client
77+
module, the application executes it and depending on the result of this execution
78+
it does the following:
79+
80+
* if the event handler returns ``true`` closes the form
81+
* if the event handler returns ``false`` leaves the form open
82+
6483

6584
Video
6685
=====
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
==============
2+
Version 5.4.39
3+
==============
4+
5+
Library:
6+
7+
* Jam.py now uses SQLAlchemy connection poll
8+
9+
* when image field read_only attribute is set user can not change the image by
10+
double-clicking on it
11+
12+
* Some bugs fixed
13+
14+
Documentation:
15+
16+
:doc:`How to lock a record so that users cannot edit it at the same time </how to/how_to_lock_record>`
17+
topic added

jam/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = (5, 4, 37)
1+
VERSION = (5, 4, 39)
22

33
def version():
44
global VERSION

jam/builder.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -510,13 +510,13 @@ <h5 class="text-center">Parameters</h5>
510510
<div class="control-group">
511511
<label class="control-label" for="inputLoging">Login</label>
512512
<div class="controls">
513-
<input type="text" id="inputLoging" name="username" tabindex="1" placeholder="логин">
513+
<input type="text" id="inputLoging" name="username" tabindex="1" placeholder="login">
514514
</div>
515515
</div>
516516
<div class="control-group">
517517
<label class="control-label" for="inputPassword">Password</label>
518518
<div class="controls">
519-
<input type="password" id="inputPassword" name="password" tabindex="2" placeholder="пароль">
519+
<input type="password" id="inputPassword" name="password" tabindex="2" placeholder="password">
520520
</div>
521521
</div>
522522
<div class="modal-footer">

jam/common.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def currency_to_str(val):
237237

238238
def str_to_currency(val):
239239
result = val.strip()
240-
if MON_THOUSANDS_SEP:
240+
if len(MON_THOUSANDS_SEP):
241241
result = result.replace(MON_THOUSANDS_SEP, '')
242242
if CURRENCY_SYMBOL:
243243
result = result.replace(CURRENCY_SYMBOL, '')

jam/dataset.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def set_text(self, value):
152152
if self.data_type == common.FLOAT:
153153
self.set_value(common.str_to_float(value))
154154
elif self.data_type == common.CURRENCY:
155-
self.set_value(common.str_to_float(value))
155+
self.set_value(common.str_to_currency(value))
156156
elif self.data_type == common.DATE:
157157
self.set_value(common.str_to_date(value))
158158
elif self.data_type == common.DATETIME:

0 commit comments

Comments
 (0)