Timesheets-Server
Timesheets server
Načítám...
Vyhledávám...
Nebylo nic nalezeno
database_plugin_fotomon.cpp
Zobrazit dokumentaci tohoto souboru.
1
7#include "msettings.h"
8#include "msqlquery.h"
9#include "json.h"
10#include "pdebug.h"
11#include <QUuid>
12#include <QSqlError>
13#include <QCryptographicHash>
14#include <QFileInfo>
15#include <QFile>
16#include <QDir>
17
18using namespace Db::Plugins;
19
20
21DatabasePluginFotomon::~DatabasePluginFotomon() {
22 close();
23}
24
25
26DatabasePluginFotomon::DatabasePluginFotomon(QObject *parent) : Db::Plugins::DatabasePlugin(parent) {
27 Q_ASSERT(parent != NULL);
28 setObjectName("DatabasePluginFotomon");
29 m_temporaryTableTicketsCreated = false;
30}
31
32
33bool DatabasePluginFotomon::open() {
34 m_db = QSqlDatabase::addDatabase("QPSQL", QUuid::createUuid().toString().toUtf8());
35
36 m_db.setDatabaseName ( m_databasename );
37 m_db.setHostName ( m_hostname );
38 m_db.setPort ( m_port );
39 m_db.setUserName ( m_username );
40 m_db.setPassword ( m_password );
41
42 if (!m_db.open()) {
43 PDEBUG << "Cannot connect to database Fotomon";
44 PDEBUG << m_db.lastError().text();
45 return false;
46 }
47
48 return true;
49}
50
51
52bool DatabasePluginFotomon::close() {
53 m_db.close();
54 return true;
55}
56
57
58void DatabasePluginFotomon::begin() {
59 MSqlQuery q(m_db);
60 q.exec("begin;");
61}
62
63
64void DatabasePluginFotomon::commit() {
65 MSqlQuery q(m_db);
66 q.exec("commit;");
67}
68
69
70QVariant DatabasePluginFotomon::currval(const QString& sequence) {
71 MSqlQuery q(m_db);
72 QVariant cv;
73 q.prepare(R"'(select currval(:sequence);)'");
74 q.bindValue(":sequence", sequence);
75 q.exec();
76 if (q.next()) {
77 cv = q.value(0);
78 }
79 return cv;
80}
81
82
83void DatabasePluginFotomon::changePassword(const QString& login, const QString& oldpassword, const QString& newpassword) {
84 Q_UNUSED(login);
85 Q_UNUSED(oldpassword);
86 Q_UNUSED(newpassword);
87}
88
89
90QList<Dbt::Users> DatabasePluginFotomon::authenticate(const QString& login, const QString& password) {
91 QString md5 = QString::fromUtf8(QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex());
92 QList<Dbt::Users> list;
93 MSqlQuery q(m_db);
94 q.prepare(R"X(
95 select "user", login, name, language
96 from users
97 where password = :password
98 and login = :login
99 and is_active
100 and not is_deleted
101 ;
102 )X");
103 q.bindValue(":login", login);
104 q.bindValue(":password", md5);
105 q.exec();
106 while (q.next()) {
107 int i=0;
108 Dbt::Users x;
109 x.user = q.value(i++).toInt();
110 x.login = q.value(i++).toString();
111 x.name = q.value(i++).toString();
112 x.lang = q.value(i++).toString();
113 list << x;
114 }
115 return list;
116}
117
118
119QList<Dbt::Users> DatabasePluginFotomon::users(int id) {
120 Q_UNUSED(id);
121 QList<Dbt::Users> list;
122 MSqlQuery q(m_db);
123 q.prepare(R"X(select "user", login, name, language from users where is_active and not is_deleted;)X");
124 q.exec();
125 while (q.next()) {
126 int i=0;
127 Dbt::Users x;
128 x.user = q.value(i++).toInt();
129 x.login = q.value(i++).toString();
130 x.name = q.value(i++).toString();
131 x.lang = q.value(i++).toString();
132 list << x;
133 }
134 return list;
135}
136
137
138void DatabasePluginFotomon::createTemporaryTableTickets(int ticket, bool all) {
139 Q_UNUSED(all);
140 if (m_temporaryTableTicketsCreated) { return; }
141 m_temporaryTableTicketsCreated = true;
142 MSqlQuery q(m_db);
143 q.exec(R"'(
144 create temporary table temporary_tickets (
145 ticket int,
146 type int,
147 system int,
148 category int,
149 date timestamp with time zone,
150 "user" int,
151 description text
152 );
153 )'");
154
155 q.prepare(R"'(
156 with
157 active_tickets as (
158 select t.ticket
159 from tickets t
160 left join lateral (select tn.ticket, tn.status from tickets_notes tn where tn.ticket = t.ticket order by ticket, date desc limit 1) tl using (ticket)
161 left join tickets_status ts on (tl.status = ts.status)
162 where (:ticket1 <= 0 or :ticket2 = t.ticket)
163 and (ts.closed is null or not ts.closed)
164 ),
165 users_systems as (
166 select us.system
167 from users_systems us, users u, systems s
168 where u."user" = :user
169 and u."user" = us."user"
170 and us.system = s.system
171 and s.show_on_web and s.show_on_panel
172 and u.is_active and not u.is_deleted
173 )
174 insert into temporary_tickets (ticket, type, system, category, date, "user", description)
175 select t.ticket, t.type, t.system, t.category, t.date, t."user",
176 case when description = '' then formal_description->0->'description'->>:lang else description end as description
177 from tickets t, users u
178 where u."user" = t."user"
179 and t.ticket in (select ticket from active_tickets)
180 and t.system in (select system from users_systems)
181 and (:ticket3 <= 0 or :ticket4 = t.ticket)
182 )'");
183 q.bindValue(":user", userId());
184 q.bindValue(":lang", userLang());
185 q.bindValue(":ticket1", ticket);
186 q.bindValue(":ticket2", ticket);
187 q.bindValue(":ticket3", ticket);
188 q.bindValue(":ticket4", ticket);
189 q.exec();
190}
191
192
193void DatabasePluginFotomon::createTemporaryTableCategories() {
194 MSqlQuery q(m_db);
195
196 q.exec("create temporary table timesheet_categories "
197 "(type int, system int, category int, description text, parent_type int)"
198 ";");
199
200 // Vybere všechny typy knih
201 q.prepare("insert into timesheet_categories (type, system, category, description, parent_type) "
202 " select type, null, null, formal_description->>:lang, 1 "
203 " from tickets_types;");
204 q.bindValue(":lang", userLang());
205 q.exec();
206
207 // Vybere všechny kombinace záznamů typ-system
208 q.prepare("insert into timesheet_categories (type, system, category, description, parent_type) "
209 " select distinct on (tt.type, s.system) tt.type, s.system, null, s.description, 2 "
210 " from tickets_categories_types_systems tt, systems s "
211 " where s.show_on_panel and s.show_on_web "
212 " and s.system in (select system from users_systems where \"user\" = :user); "
213 );
214 q.bindValue(":user", userId());
215 q.exec();
216
217 // Vybere všechny kombinace záznamů typ-system-kategorie, kde EXISTUJE záznam typ-system
218 q.prepare("insert into timesheet_categories (type, system, category, description, parent_type) "
219 " select tt.type, s.system, tc.category, tc.formal_description->>:lang, 3 "
220 " from tickets_categories_types_systems tt, systems s, tickets_categories tc "
221 " where tt.system = s.system "
222 " and tc.category = tt.category "
223 " and s.show_on_panel and s.show_on_web "
224 " and s.system in (select system from users_systems where \"user\" = :user); "
225 );
226 q.bindValue(":lang", userLang());
227 q.bindValue(":user", userId());
228 q.exec();
229
230 // Vybere všechny kombinace záznamů typ-system-kategorie, kde NEEXISTUJE záznam typ-system
231 q.prepare("insert into timesheet_categories (type, system, category, description, parent_type) "
232 " select tt.type, s.system, tc.category, tc.formal_description->>:lang, 4 "
233 " from systems s, tickets_types tt, tickets_categories tc "
234 " where s.show_on_panel and s.show_on_web "
235 " and s.system in (select system from users_systems where \"user\" = :user) "
236 " and not exists (select 1 "
237 " from tickets_categories_types_systems tcts "
238 " where tcts.type = tt.type "
239 " and tcts.system = s.system ); "
240 );
241 q.bindValue(":user", userId());
242 q.bindValue(":lang", userLang());
243 q.exec();
244
245}
246
247
248QString DatabasePluginFotomon::categoryKey(const QVariant& type, const QVariant& system, const QVariant& category, int parent_type) {
249 if (parent_type == 1) {
250 return QString(R"'({"type":%1})'")
251 .arg(type.toInt())
252 ;
253 }
254
255 if (parent_type == 2) {
256 return QString(R"'({"type":%1,"system":%2})'")
257 .arg(type.toInt())
258 .arg(system.toInt())
259 ;
260 }
261
262 if (parent_type == 3) {
263 return QString(R"'({"type":%1,"system":%2,"category":%3})'")
264 .arg(type.toInt())
265 .arg(system.toInt())
266 .arg(category.toInt())
267 ;
268 }
269
270 if (parent_type == 4) {
271 return QString(R"'({"type":%1,"system":%2,"category":%3})'")
272 .arg(type.toInt())
273 .arg(system.toInt())
274 .arg(category.toInt())
275 ;
276 }
277
278 return QString();
279}
280
281
282QString DatabasePluginFotomon::parentCategoryKey(const QVariant& type, const QVariant& system, const QVariant& category, int parent_type) {
283 Q_UNUSED(category);
284 if (parent_type == 1) {
285 return QString();
286 }
287
288 if (parent_type == 2) {
289 return QString(R"'({"type":%1})'")
290 .arg(type.toInt())
291 ;
292 }
293
294 if (parent_type == 3) {
295 return QString(R"'({"type":%1,"system":%2})'")
296 .arg(type.toInt())
297 .arg(system.toInt())
298 ;
299 }
300
301 if (parent_type == 4) {
302 return QString(R"'({"type":%1,"system":%2})'")
303 .arg(type.toInt())
304 .arg(system.toInt())
305 ;
306 }
307
308 return QString();
309}
310
311
312QList<Dbt::Categories> DatabasePluginFotomon::categoriesToRoot(const QString& id) {
313 Q_UNUSED(id);
314 QList<Dbt::Categories> list;
315 return list;
316}
317
318
319QList<Dbt::Categories> DatabasePluginFotomon::categories(const QString& id) {
320 Q_UNUSED(id);
321 createTemporaryTableCategories();
322
323 QList<Dbt::Categories> list;
324 MSqlQuery q(m_db);
325
326 q.exec("select type, system, category, description, parent_type from timesheet_categories;");
327 while (q.next()) {
329 QVariant type = q.value(0);
330 QVariant system = q.value(1);
331 QVariant category = q.value(2);
332 QVariant description = q.value(3);
333 int parent_type = q.value(4).toInt();
334
335 x.category = categoryKey(type, system, category, parent_type);
336 x.parent_category = parentCategoryKey(type, system, category, parent_type);
337 x.description = description.toString();
338 list << x;
339 }
340
341 PDEBUG << "pocet kategorii" << list.size();
342 return list;
343}
344
345
346QList<Dbt::Categories> DatabasePluginFotomon::subcategories(const QString& id) {
347 Q_UNUSED(id);
348 QList<Dbt::Categories> list;
349 return list;
350}
351
352
353QList<Dbt::Categories> DatabasePluginFotomon::siblingcategories(const QString& id) {
354 Q_UNUSED(id);
355 QList<Dbt::Categories> list;
356 return list;
357}
358
359
360QList<Dbt::StatusOrder> DatabasePluginFotomon::statusOrder(const QString& id) {
361 Q_UNUSED(id);
362 createTemporaryTableCategories();
363
364 QList<Dbt::StatusOrder> list;
365 MSqlQuery q(m_db);
366
367 q.exec("select c.type, c.system, c.category, c.description, c.parent_type, "
368 " s.status_from, s.status_to "
369 " from timesheet_categories c, tickets_types_status s"
370 " where c.type = s.type "
371 ";");
372 while (q.next()) {
374 QVariant type = q.value(0);
375 QVariant system = q.value(1);
376 QVariant category = q.value(2);
377 QVariant description = q.value(3);
378 int parent_type = q.value(4).toInt();
379
380 x.previous_status = q.value(5);
381 x.next_status = q.value(6);
382 x.category = categoryKey(type, system, category, parent_type);
383 list << x;
384 }
385
386 PDEBUG << "pocet prechodu" << list.size();
387 return list;
388
389}
390
391
392QList<Dbt::Statuses> DatabasePluginFotomon::statuses(const QString& id) {
393 Q_UNUSED(id);
394 QList<Dbt::Statuses> list;
395 MSqlQuery q(m_db);
396
397 q.prepare("select ts.status, ts.formal_description->>:lang, ts.abbreviation, ts.color "
398 " from tickets_status ts "
399 ";");
400 q.bindValue(":lang", userLang());
401 q.exec();
402 while (q.next()) {
404 int i=0;
405 x.status = q.value(i++).toString();
406 x.description = q.value(i++).toString();
407 x.abbreviation = q.value(i++).toString();
408 x.color = q.value(i++).toString();
409 list << x;
410 }
411
412 return list;
413}
414
415
416QList<Dbt::Statuses> DatabasePluginFotomon::statuses(const QString& category, const QString& prevstatus) {
417 Q_UNUSED(category);
418 Q_UNUSED(prevstatus);
419 return statuses(QString());
420}
421
422
423QList<Dbt::StatusTemplates> DatabasePluginFotomon::statusTemplates(int id) {
424 MSqlQuery q(m_db);
425 QList<Dbt::StatusTemplates> list;
426
427 /* Too large document :-(
428 createTemporaryTableCategories();
429 q.prepare(R"X(select t.note_template, t.status, c.category, t.code, t.title->>:lang, t.description
430 from timesheet_categories c, tickets_notes_templates t
431 where c.type = t.type
432 and (t.note_template = :id1 or 0 > :id2)
433 )X");
434 */
435
436 q.prepare(R"X(select note_template, status, null, code, title->>:lang, description
437 from tickets_notes_templates
438 where note_template = :id1 or 0 > :id2;
439 )X");
440
441
442 q.bindValue(":id1", id);
443 q.bindValue(":id2", id);
444 q.bindValue(":lang", userLang());
445 q.exec();
446 while (q.next()) {
448 int i=0;
449 x.id = q.value(i++).toInt();
450 x.status = q.value(i++).toString();
451 x.category = q.value(i++).toString();
452 x.code = q.value(i++).toString();
453 x.title = q.value(i++).toString();
454 x.description = q.value(i++).toString();
455 list << x;
456 }
457
458 return list;
459}
460
461
462QList<Dbt::Tickets> DatabasePluginFotomon::tickets(bool all) {
463 return tickets(-1, all);
464}
465
466
467QList<Dbt::Tickets> DatabasePluginFotomon::tickets(int ticket, bool all) {
468 PDEBUG;
469 createTemporaryTableTickets(ticket, all);
470 QList<Dbt::Tickets> list;
471 MSqlQuery q(m_db);
472
473 q.prepare(R"X(select ticket, type, system, 1, date, description from temporary_tickets;)X");
474 q.exec();
475 while (q.next()) {
476 Dbt::Tickets x;
477 int i=0;
478 x.ticket = q.value(i++);
479 QVariant type = q.value(i++);
480 QVariant system = q.value(i++);
481 QVariant category = q.value(i++);
482 x.category = categoryKey(type, system, category, 3);
483 x.date = q.value(i++).toDateTime();
484 x.description = q.value(i++).toString();
485 list << x;
486 }
487 return list;
488}
489
490
491QList<Dbt::Tickets> DatabasePluginFotomon::tickets(const Dbt::Categories&, bool all) {
492 return tickets(-1, all);
493}
494
495
496QList<Dbt::TicketsVw> DatabasePluginFotomon::ticketsVw(const Dbt::Categories&, bool all) {
497 return ticketsVw(-1, all);
498}
499
500
501QList<Dbt::TicketsVw> DatabasePluginFotomon::ticketsVw(bool all) {
502 Q_UNUSED(all);
503 return ticketsVw(-1, all);
504}
505
506
507QList<Dbt::TicketsVw> DatabasePluginFotomon::ticketsVw(int ticket, bool all) {
508 createTemporaryTableTickets(ticket, all);
509 QList<Dbt::Tickets> list1;
510 QList<Dbt::TicketsVw> list;
511 MSqlQuery q(m_db);
512
513 q.prepare(R"X(select ticket, type, system, category, date, description, "user" from temporary_tickets;)X");
514 q.exec();
515 while (q.next()) {
517 int i=0;
518 x.ticket = q.value(i++);
519 QVariant type = q.value(i++);
520 QVariant system = q.value(i++);
521 QVariant category = q.value(i++);
522 x.category = categoryKey(type, system, category, 3);
523 x.date = q.value(i++).toDateTime();
524 x.description = q.value(i++).toString();
525 x.user = q.value(i++).toInt();
526 list1 << x;
527 }
528 for (int i=0; i<list1.size(); i++) {
529 Dbt::TicketsVw x = list1[i];
530 x.timesheets = ticketTimesheets(list1[i].ticket.toInt(), all);
531 x.statuses = ticketStatus(list1[i].ticket.toInt(), all);
532 x.values = ticketValues(list1[i].ticket.toInt(), all);
533 x.files = ticketFiles(list1[i].ticket.toInt(), all);
534 list << x;
535 }
536
537 return list;
538}
539
540
541QVariant DatabasePluginFotomon::save(const Dbt::Tickets& data) {
542 MSqlQuery q(m_db);
543
544 QVariantMap x = JSON::data(data.category.toByteArray()).toMap();
545 int type = x["type"].toInt();
546 int system = x["system"].toInt();
547 int category = x["category"].toInt();
548
549 bool found = false;
550 if (!data.created) {
551 q.prepare(R"'(select 1 from tickets where ticket = :ticket;)'");
552 q.bindValue(":ticket", data.ticket);
553 q.exec();
554 found = q.next();
555 }
556
557 if (!data.created && found) {
558 q.prepare(R"'(
559 update tickets set
560 type = :type,
561 system = :system,
562 category = :category,
563 date = :date,
564 price = :price,
565 description = :description,
566 "user" = :user
567 where ticket = :ticket
568 )'");
569 q.bindValue(":type", type);
570 q.bindValue(":system", system);
571 q.bindValue(":category", category);
572 q.bindValue(":date", data.date);
573 q.bindValue(":price", data.price);
574 q.bindValue(":description", data.description);
575 q.bindValue(":user", data.user);
576 q.bindValue(":ticket", data.ticket);
577 q.exec();
578 return QVariant(data.ticket);
579 }
580
581 if (data.created || !found) {
582 q.prepare(R"'(
583 insert into tickets (type, system, category, date, price, description, "user")
584 values (:type, :system, :category, :date, :price, :description, :user);
585 )'");
586 q.bindValue(":type", type);
587 q.bindValue(":system", system);
588 q.bindValue(":category", category);
589 q.bindValue(":date", data.date);
590 q.bindValue(":price", data.price);
591 q.bindValue(":description", data.description);
592 q.bindValue(":user", data.user);
593 q.exec();
594 return currval("tickets_ticket_seq");
595 }
596
597 Q_UNREACHABLE();
598 qFatal("Should not happen");
599 return QVariant();
600
601}
602
603template<typename T>
604QList<T> remapTicket(const QList<T>& input, int ticket) {
605 QList<T> list;
606 QListIterator<T> iterator(input);
607 while (iterator.hasNext()) {
608 T x = iterator.next();
609 x.ticket = ticket;
610 if (ticket <= 0) { x.id = 0; }
611 list << x;
612 }
613 return list;
614}
615
616
617QVariant DatabasePluginFotomon::save(const Dbt::TicketsVw& data) {
618 MSqlQuery q(m_db);
619 q.begin();
620 int ticket = save(dynamic_cast<const Dbt::Tickets&>(data)).toInt();
621 save(remapTicket(data.timesheets, ticket));
622 save(remapTicket(data.statuses, ticket));
623 save(remapTicket(data.values, ticket));
624 save(remapTicket(data.files, ticket));
625 q.commit();
626
627 return QVariant();
628}
629
630
631void DatabasePluginFotomon::remove(const Dbt::Tickets& id) {
632 MSqlQuery q(m_db);
633 q.prepare(R"'(delete from tickets where ticket = :id;)'");
634 q.bindValue(":id", id.ticket);
635 q.exec();
636}
637
638
639QList<Dbt::TicketStatus> DatabasePluginFotomon::ticketStatus(int ticket, bool all) {
640 createTemporaryTableTickets(ticket, all);
641 QList<Dbt::TicketStatus> list;
642 MSqlQuery q(m_db);
643
644 q.prepare(R"'(
645 select tn.note, tn.ticket, t."user", tn.date, tn.status,
646 case when tn.description != '' then tn.description else tn.formal_description->0->'description'->>'cs' end as description,
647 tn.formal_description,
648 ts.description, ts.color
649 from tickets_notes tn, temporary_tickets t, tickets_status ts
650 where tn.ticket = t.ticket
651 and ts.status = tn.status
652 and (:ticket1 <= 0 or :ticket2 = t.ticket)
653 ;
654 )'");
655 q.bindValue(":user", userId());
656 q.bindValue(":lang", userLang());
657 q.bindValue(":ticket1", ticket);
658 q.bindValue(":ticket2", ticket);
659 q.exec();
660 while (q.next()) {
662 int i=0;
663 x.id = q.value(i++).toInt();
664 x.ticket = q.value(i++).toInt();
665 x.user = q.value(i++).toInt();
666 x.date = q.value(i++).toDateTime();
667 x.status = q.value(i++).toString();
668 x.description = q.value(i++).toString();
669 x.description2 = JSON::data(q.value(i++).toString().toUtf8()).toMap();
670 x.status_description = q.value(i++).toString();
671 x.status_color = q.value(i++).toString();
672 // bool status_closed;
673 // bool status_can_be_run;
674 // bool status_ignored;
675 list << x;
676 }
677 return list;
678}
679
680
681QList<Dbt::TicketStatus> DatabasePluginFotomon::ticketStatus(bool all) {
682 Q_UNUSED(all);
683 return ticketStatus(-1, all);
684}
685
686
687QList<Dbt::TicketStatus> DatabasePluginFotomon::ticketStatus(int id) {
688 Q_UNUSED(id);
689 QList<Dbt::TicketStatus> list;
690 return list;
691}
692
693
694QVariant DatabasePluginFotomon::save(const Dbt::TicketStatus& data) {
695 MSqlQuery q(m_db);
696
697 bool found = false;
698 if (!data.created) {
699 q.prepare(R"'(select 1 from tickets_notes where note = :id;)'");
700 q.bindValue(":id", data.id);
701 q.exec();
702 found = q.next();
703 }
704
705 if (!data.created && found) {
706 QByteArray description2 = JSON::json(data.description2);
707 if (description2 == "{}") { description2 = ""; }
708 q.prepare(QString(R"'(
709 update tickets_notes set
710 ticket = :ticket,
711 "user" = :user,
712 date = :date,
713 description = :description,
714 formal_description = %1,
715 status = :status
716 where note = :id
717 )'").arg((description2=="") ? "null" : QString("'%1'").arg(QString::fromUtf8(description2)) ) );
718 q.bindValue(":id", data.id);
719 q.bindValue(":user", data.user);
720 q.bindValue(":ticket", data.ticket);
721 q.bindValue(":date", data.date);
722 q.bindValue(":description", data.description);
723 q.bindValue(":status", data.status);
724 q.exec();
725 return QVariant(data.id);
726 }
727
728 if (data.created || !found) {
729 QByteArray description2 = JSON::json(data.description2);
730 if (description2 == "{}") { description2 = ""; }
731 q.prepare(QString(R"'(
732 insert into tickets_notes (ticket, "user", date, description, status, formal_description)
733 values (:ticket, :user, :date, :description, :status, %1)
734 )'").arg((description2=="") ? "null" : QString("'%1'").arg(QString::fromUtf8(description2)) ) );
735 q.bindValue(":user", data.user);
736 q.bindValue(":ticket", data.ticket);
737 q.bindValue(":date", data.date);
738 q.bindValue(":description", data.description);
739 q.bindValue(":status", data.status);
740 q.exec();
741
742 return currval("tickets_notes_note_seq");
743 }
744
745 Q_UNREACHABLE();
746 return QVariant();
747}
748
749
750QList<Dbt::TicketTimesheets> DatabasePluginFotomon::ticketTimesheets(int ticket, bool all) {
751 createTemporaryTableTickets(ticket, all);
752 QList<Dbt::TicketTimesheets> list;
753 MSqlQuery q(m_db);
754 q.prepare(R"'(
755 select tt.id, tt.ticket, tt."user", tt.date_from, tt.date_to
756 from temporary_tickets t, ticket_timesheets tt
757 where t.ticket = tt.ticket
758 and t.ticket = :ticket
759 ;
760 )'");
761 q.bindValue(":user", userId());
762 q.bindValue(":ticket", ticket);
763 q.exec();
764 while (q.next()) {
765 int i=0;
767 x.id = q.value(i++).toInt();
768 x.ticket = q.value(i++).toInt();
769 x.user = q.value(i++).toInt();
770 x.date_from = q.value(i++).toDateTime();
771 x.date_to = q.value(i++).toDateTime();
772 list << x;
773 }
774 return list;
775}
776
777
778QList<Dbt::TicketTimesheets> DatabasePluginFotomon::ticketTimesheets(int id) {
779 QList<Dbt::TicketTimesheets> list;
780 MSqlQuery q(m_db);
781 q.prepare(R"'(
782 select tt.id, tt.ticket, tt."user", tt.date_from, tt.date_to
783 from ticket_timesheets tt, tickets t, users_categories uc
784 where t.ticket = tt.ticket
785 and t.category = uc.category
786 and uc."user" = :user
787 and :id = tt.id
788 ;
789 )'");
790 q.bindValue(":user", userId());
791 q.bindValue(":id", id);
792 q.exec();
793 while (q.next()) {
794 int i=0;
796 x.id = q.value(i++).toInt();
797 x.ticket = q.value(i++).toInt();
798 x.user = q.value(i++).toInt();
799 x.date_from = q.value(i++).toDateTime();
800 x.date_to = q.value(i++).toDateTime();
801 list << x;
802 }
803 return list;
804}
805
806
807QList<Dbt::TicketTimesheets> DatabasePluginFotomon::ticketTimesheets(bool all) {
808 return ticketTimesheets(-1, all);
809}
810
811
812QList<Dbt::TicketTimesheets> DatabasePluginFotomon::runningTimesheets(int ticket) {
813 Q_UNUSED(ticket);
814 return QList<Dbt::TicketTimesheets>();
815}
816
817
818QList<Dbt::TicketTimesheets> DatabasePluginFotomon::startTimesheet(int ticket) {
819 Q_UNUSED(ticket);
820 return QList<Dbt::TicketTimesheets>();
821}
822
823
824QList<Dbt::TicketTimesheets> DatabasePluginFotomon::stopTimesheet(int ticket) {
825 Q_UNUSED(ticket);
826 return QList<Dbt::TicketTimesheets>();
827}
828
829
830QList<Dbt::TicketTimesheets> DatabasePluginFotomon::toggleTimesheet(int ticket) {
831 Q_UNUSED(ticket);
832 return QList<Dbt::TicketTimesheets>();
833}
834
835
836QVariant DatabasePluginFotomon::save(const Dbt::TicketTimesheets& data) {
837 MSqlQuery q(m_db);
838
839 bool found = false;
840 if (!data.created) {
841 q.prepare(R"'(select 1 from ticket_timesheets where id = :id;)'");
842 q.bindValue(":id", data.id);
843 q.exec();
844 found = q.next();
845 }
846
847 if (!data.created && found) {
848 q.prepare(R"'(
849 update ticket_timesheets set
850 ticket = :ticket,
851 "user" = :user,
852 date_from = :date_from,
853 date_to = :date_to
854 where id = :id
855 )'");
856 q.bindValue(":id", data.id);
857 q.bindValue(":user", data.user);
858 q.bindValue(":ticket", data.ticket);
859 q.bindValue(":date_from", data.date_from);
860 q.bindValue(":date_to", data.date_to);
861 q.exec();
862 return QVariant(data.id);
863 }
864
865
866 if (data.created || !found) {
867 q.prepare(R"'(
868 insert into ticket_timesheets (ticket, "user", date_from, date_to)
869 values (:ticket, :user, :date_from, :date_to)
870 )'");
871 q.bindValue(":user", data.user);
872 q.bindValue(":ticket", data.ticket);
873 q.bindValue(":date_from", data.date_from);
874 q.bindValue(":date_to", data.date_to);
875 q.exec();
876
877 return currval("ticket_timesheets_id_seq");
878 }
879
880 Q_UNREACHABLE();
881 return QVariant();
882}
883
884
885void DatabasePluginFotomon::remove(const Dbt::TicketTimesheets& id) {
886 MSqlQuery q(m_db);
887 q.prepare(R"'(delete from ticket_timesheets where id = :id;)'");
888 q.bindValue(":id", id.id);
889 q.exec();
890}
891
892
893QByteArray DatabasePluginFotomon::fileContent(const QString& filename) {
894 QByteArray content;
895 QDir dir(MSETTINGS->dbFilesDirectory());
896 QString fullfilename = dir.absoluteFilePath(filename);
897 QFile file(fullfilename);
898 if (file.open(QIODevice::ReadOnly)) {
899 content = file.readAll();
900 file.close();
901 }
902 return content;
903}
904
905
906QList<Dbt::TicketFiles> DatabasePluginFotomon::ticketFiles(int ticket, bool all) {
907 createTemporaryTableTickets(ticket, all);
908 QList<Dbt::TicketFiles> list;
909 MSqlQuery q(m_db);
910
911 q.prepare(R"'(
912 select f.file, f.upload_date, tf.ticket, f.origname, f.filetype, f.filename
913 from temporary_tickets t, tickets_files tf, files f
914 where t.ticket = tf.ticket
915 and tf.file = f.file;
916 ;
917 )'");
918 q.exec();
919 while (q.next()) {
920 int i=0;
922 x.id = q.value(i++).toInt();
923 x.user = userId();
924 x.date = q.value(i++).toDateTime();
925 x.ticket = q.value(i++).toInt();
926 x.name = q.value(i++).toString();
927 x.type = q.value(i++).toString();
928 x.content = DatabasePluginFotomon::fileContent(q.value(i++).toString());
929 list << x;
930 }
931
932 return list;
933}
934
935
936QList<Dbt::TicketFiles> DatabasePluginFotomon::ticketFiles(int id) {
937 QList<Dbt::TicketFiles> list;
938 MSqlQuery q(m_db);
939
940 q.prepare(R"'(
941 select f.file, f.upload_date, tf.ticket, f.origname, f.filetype, f.filename
942 from tickets_files tf, files f, users u, tickets t, users_categories uc
943 where f.file = :id
944 and tf.file = f.file
945 and t.ticket = tf.ticket
946 and t.category = uc.category
947 and t."user" = :user
948 ;
949 )'");
950 q.bindValue(":id", id);
951 q.bindValue(":user", userId());
952 q.exec();
953 while (q.next()) {
954 int i=0;
956 x.id = q.value(i++).toInt();
957 x.user = userId();
958 x.date = q.value(i++).toDateTime();
959 x.ticket = q.value(i++).toInt();
960 x.name = q.value(i++).toString();
961 x.type = q.value(i++).toString();
962 x.content = DatabasePluginFotomon::fileContent(q.value(i++).toString());
963 list << x;
964 }
965
966 return list;
967}
968
969
970QList<Dbt::TicketFiles> DatabasePluginFotomon::ticketFiles(bool all) {
971 return ticketFiles(-1, all);
972}
973
974
975QString DatabasePluginFotomon::suffixFromType(const QString& type) {
976 if (type == "image/png") { return ".png"; }
977 if (type == "image/jpeg") { return ".jpeg"; }
978 if (type == "image/gif") { return ".gif"; }
979 return "";
980
981}
982
983QVariant DatabasePluginFotomon::save(const Dbt::TicketFiles& data) {
984 MSqlQuery q(m_db);
985
986 bool found = false;
987 q.prepare(R"'(select file from tickets_files where file = :file and ticket = :ticket;)'");
988 q.bindValue(":id", data.id);
989 q.bindValue(":ticket", data.ticket);
990 q.exec();
991 found = q.next();
992
993 // Save file
994 QString suffix = suffixFromType(data.type);
995 QString webalizedName = QString("ta%1-%2%3")
996 .arg(data.ticket.toInt())
997 .arg(QUuid::createUuid().toString().remove(QChar('{')).remove(QChar('}')))
998 .arg(suffix)
999 ;
1000 QDir dir(MSETTINGS->dbFilesDirectory());
1001 QString filename = dir.absoluteFilePath(webalizedName);
1002 QFile file(filename);
1003 if (file.open(QIODevice::WriteOnly)) {
1004 file.write(data.content);
1005 file.close();
1006 }
1007 QFileInfo info(filename);
1008 PDEBUG << webalizedName << filename << info.fileName();
1009
1010 if (found) {
1011 PDEBUG << "update files" << data.id << data.ticket;
1012 q.prepare(R"'(
1013 update files set
1014 filename = :filename,
1015 upload_date = :date,
1016 origname = :name,
1017 filetype = :type,
1018 filesize = :size
1019 where file = :fileid
1020 )'");
1021 q.bindValue(":filename", info.fileName());
1022 q.bindValue(":date", data.date);
1023 q.bindValue(":name", data.name + suffix);
1024 q.bindValue(":type", data.type);
1025 q.bindValue(":size", info.size());
1026 q.bindValue(":fileid", data.id);
1027 q.bindValue(":ticket", data.ticket);
1028 q.exec();
1029 return QVariant(data.id);
1030 }
1031
1032 if (!found) {
1033 q.prepare(R"'(
1034 insert into files (filename, upload_date, origname, filetype, filesize)
1035 values (:filename, :date, :name, :type, :sizeticket);
1036 )'");
1037 q.bindValue(":filename", info.fileName());
1038 q.bindValue(":date", data.date);
1039 q.bindValue(":name", data.name + suffix);
1040 q.bindValue(":type", data.type);
1041 q.bindValue(":size", info.size());
1042 q.exec();
1043
1044 q.prepare(R"'(
1045 insert into tickets_files (ticket, file) select :ticket, currval('files_file_seq');
1046 )'");
1047 q.bindValue(":ticket", data.ticket);
1048 q.exec();
1049
1050 QVariant rc = currval("files_file_seq");
1051 PDEBUG << "insert files" << rc.toInt() << data.ticket;
1052 return rc;
1053 }
1054
1055 Q_UNREACHABLE();
1056 return QVariant();
1057}
1058
1059
1060void DatabasePluginFotomon::remove(const Dbt::TicketFiles& id) {
1061 MSqlQuery q(m_db);
1062 q.prepare(R"'(delete from ticket_images where id = :id;)'");
1063 q.bindValue(":id", id.id);
1064 q.exec();
1065}
1066
1067
1068QList<Dbt::TicketValues> DatabasePluginFotomon::ticketValues(int ticket, bool all) {
1069 createTemporaryTableTickets(ticket, all);
1070 QList<Dbt::TicketValues> list;
1071 MSqlQuery q(m_db);
1072 q.prepare(R"'(
1073 select tv.id, tt.ticket, tv.name, tv.value, tv."user", tv.date
1074 from temporary_tickets tt, ticket_values tv
1075 where tt.ticket = tv.ticket
1076 ;
1077 )'");
1078 q.exec();
1079 while (q.next()) {
1080 int i=0;
1082 x.id = q.value(i++).toInt();
1083 x.ticket = q.value(i++).toInt();
1084 x.name = q.value(i++).toString();
1085 x.value = JSON::data(q.value(i++).toByteArray());
1086 x.user = q.value(i++).toInt();
1087 x.date = q.value(i++).toDateTime();
1088 list << x;
1089 }
1090 return list;
1091}
1092
1093
1094QList<Dbt::TicketValues> DatabasePluginFotomon::ticketValues(int id) {
1095 QList<Dbt::TicketValues> list;
1096 MSqlQuery q(m_db);
1097 q.prepare(R"'(
1098 select tv.id, tv.ticket, tv.date, tv.name, tv.value, tv."user"
1099 from tickets tt, ticket_values tv, users_categories uc
1100 where tt.ticket = tv.ticket
1101 and tt.category = uc.category
1102 and uc.user = :user
1103 and :id = tv.id
1104 ;
1105 )'");
1106 q.bindValue(":id", id);
1107 q.bindValue(":user", userId());
1108 q.exec();
1109 while (q.next()) {
1110 int i=0;
1112 x.id = q.value(i++).toInt();
1113 x.ticket = q.value(i++).toInt();
1114 x.date = q.value(i++).toDateTime();
1115 x.name = q.value(i++).toString();
1116 x.value = JSON::data(q.value(i++).toByteArray());
1117 x.user = q.value(i++).toInt();
1118 list << x;
1119 }
1120 return list;
1121}
1122
1123
1124QList<Dbt::TicketValues> DatabasePluginFotomon::ticketValues(bool all) {
1125 return ticketValues(-1, all);
1126}
1127
1128
1129QVariant DatabasePluginFotomon::save(const Dbt::TicketValues& data) {
1130 MSqlQuery q(m_db);
1131
1132 bool found = false;
1133 if (!data.created) {
1134 q.prepare(R"'(select 1 from ticket_values where id = :id;)'");
1135 q.bindValue(":id", data.id);
1136 q.exec();
1137 found = q.next();
1138 }
1139
1140 if (!data.created && found) {
1141 q.prepare(QString(R"'(
1142 update ticket_values set
1143 ticket = :ticket,
1144 "user" = :user,
1145 date = :date,
1146 name = :name,
1147 value = '%1'
1148 where id = :id
1149 )'").arg(QString::fromUtf8(JSON::json(data.value))));
1150 q.bindValue(":id", data.id);
1151 q.bindValue(":ticket", data.ticket);
1152 q.bindValue(":user", data.user);
1153 q.bindValue(":date", data.date);
1154 q.bindValue(":name", data.name);
1155 // q.bindValue(":value", JSON::json(data.value));
1156 q.exec();
1157 return QVariant(data.id);
1158 }
1159
1160 if (data.created || !found) {
1161 q.prepare(QString(R"'(
1162 insert into ticket_values (ticket, "user", date, name, value)
1163 select :ticket, :user, :date, :name, '%1'
1164 where not exists (select 1 from ticket_values where id = :id);
1165 )'").arg(QString::fromUtf8(JSON::json(data.value))));
1166 q.bindValue(":id", data.id);
1167 q.bindValue(":ticket", data.ticket);
1168 q.bindValue(":user", data.user);
1169 q.bindValue(":date", data.date);
1170 q.bindValue(":name", data.name);
1171 // q.bindValue(":value", JSON::json(data.value));
1172 q.exec();
1173
1174 return currval("ticket_values_id_seq");
1175 }
1176
1177 Q_UNREACHABLE();
1178 return QVariant();
1179}
1180
1181
1182void DatabasePluginFotomon::remove(const Dbt::TicketValues& id) {
1183 MSqlQuery q(m_db);
1184 q.prepare(R"'(delete from ticket_values where id = :id;)'");
1185 q.bindValue(":id", id.id);
1186 q.exec();
1187}
1188
1189
1190QList<Dbt::UsersCategories> DatabasePluginFotomon::usersCategories(int id, int user, const QString& category) {
1191 Q_UNUSED(id);
1192 Q_UNUSED(user);
1193 Q_UNUSED(category);
1194 QList<Dbt::UsersCategories> list;
1195 return list;
1196}
1197
1198
1199QList<Dbt::ClientSettings> DatabasePluginFotomon::clientSettings() {
1200 QList<Dbt::ClientSettings> list;
1201 MSqlQuery q(m_db);
1202
1203 q.prepare(R"'(
1204 select multiple_timesheets, show_price, can_change_category, edit_categories,
1205 show_multiple_timesheets, show_show_price, show_can_change_category, show_edit_categories
1206 from ticket_client_settings;
1207 )'");
1208 q.exec();
1209 while (q.next()) {
1211 int i = 0;
1212 x.multiple_timesheets = q.value(i++).toBool();
1213 x.show_price = q.value(i++).toBool();
1214 x.can_change_category = q.value(i++).toBool();
1215 x.edit_categories = q.value(i++).toBool();
1216 x.show_multiple_timesheets = q.value(i++).toBool();
1217 x.show_show_price = q.value(i++).toBool();
1218 x.show_can_change_category = q.value(i++).toBool();
1219 x.show_edit_categories = q.value(i++).toBool();
1220 list << x;
1221 }
1222 return list;
1223}
1224
1225
1226QList<Dbt::CategoriesOverview> DatabasePluginFotomon::categoriesOverview(const QStringList& statuses) {
1227 Q_UNUSED(statuses);
1228 QList<Dbt::CategoriesOverview> list;
1229 return list;
1230}
1231
1232
1233QList<Dbt::Overview> DatabasePluginFotomon::overview(const QString& category, const QStringList& statuses) {
1234 Q_UNUSED(statuses);
1235 QList<Dbt::Overview> list;
1236 return list;
1237}
1238
1239
1240QList<Dbt::Overview> DatabasePluginFotomon::overview(const QString& overviewId) {
1241 Q_UNUSED(overviewId);
1242 QList<Dbt::Overview> list;
1243 return list;
1244}
1245
1246
1247QList<Dbt::OverviewList> DatabasePluginFotomon::overviewList() {
1248 QList<Dbt::OverviewList> list;
1249 return list;
1250}
1251
1252
1253
Vlastní rozšíření QSqlQuery o primitivní transakce a logování
Definition msqlquery.h:18
static QVariant data(const QByteArray &json)
Converts json to data.
Definition json.cpp:69
static QByteArray json(const QVariant &data)
Converts data to json.
Definition json.cpp:21