Compare commits

...

220 Commits

Author SHA1 Message Date
johnnyq
7bf6151d7b If login key is set and it is not provided show Client Email instead of just Email for placeholder 2026-01-17 15:13:44 -05:00
johnnyq
c6ef473edf Allow use of login key only for agents 2026-01-17 15:13:44 -05:00
johnnyq
c2020afb58 Fix White Label not displaying on the login page 2026-01-17 15:13:44 -05:00
johnnyq
71ea510841 Updated changelog 2026-01-17 15:13:44 -05:00
johnnyq
e51f840824 Added Reset favicon 2026-01-17 15:13:44 -05:00
johnnyq
76e355a4c7 Update changelog and bump app version to 25.12.1 2026-01-17 15:13:44 -05:00
johnnyq
b830baac35 Fixed Adding Payment provider not adding an account, now adding you can customize the income/expense account, expense category, and Expense vendor. Moved Saved Payment Provider Methods into Payment Providers as a link instead of on the admin side nav. Same with AI Provider and AI Models. 2026-01-17 15:13:44 -05:00
johnnyq
cd8a007b09 Refine DB Helpers 2026-01-17 15:13:44 -05:00
johnnyq
01c6c69d21 Add DB helpers to make MySQLi Prepared statements less bloated and require less code 2026-01-17 15:13:44 -05:00
johnnyq
7fd8c0fbac Fix New ticket button in contact details in the related tickets section 2026-01-17 15:13:43 -05:00
johnnyq
a04065bfce Update legacy client login links to use the new unified login method 2026-01-17 15:13:43 -05:00
wrongecho
48c2d8552a Update + credit 2026-01-17 15:13:43 -05:00
johnnyq
62d19654c0 Unify Agent and Client login, if same user exists as a client and an agent then offer a selection of client portal or agent portal 2026-01-17 15:13:43 -05:00
johnnyq
ce48632bdf refined php-xml ext notice 2026-01-17 15:13:43 -05:00
johnnyq
816800d673 Added php-xml as a requirement 2026-01-17 15:13:43 -05:00
johnnyq
24a1122b77 Added a few more things to the changelog 2026-01-17 15:13:43 -05:00
johnnyq
74a606a3fe Bump Version for 25.12 updated changelog 2026-01-17 15:13:43 -05:00
wrongecho
96116801b2 Mail queue - minor comment syntax error 2026-01-17 15:13:43 -05:00
wrongecho
2ecd165970 Mail queue - introduce a --no-mx-validation flag to bypass recipient domain MX validation 2026-01-17 15:13:43 -05:00
wrongecho
19b4598fae Ticket merge input - strip text 2026-01-17 15:13:43 -05:00
johnnyq
a714f736e5 Hide Permission Modules on sidenav admin menu as this is not ready for custom modules 2026-01-17 15:13:42 -05:00
johnnyq
7ec4f4ff4f Add CSV Escaping to the Sample Export CSV Files 2026-01-17 15:13:42 -05:00
johnnyq
7f928533df Convert all Import / Export Modals to Ajax and a few other lingering modals that were not converted yet 2026-01-17 15:13:41 -05:00
johnnyq
3b994a58af Migrate Import/export clients to ajax-modals 2026-01-17 15:13:41 -05:00
johnnyq
c13b8fcff3 Converted all Document Link Modals to the new ajax-modal, also switched trash icons for unlink icons in document details 2026-01-17 15:13:40 -05:00
johnnyq
879c16b6e1 Bump TinyMCE from 8.2.0 to 8.2.2 2026-01-17 15:13:40 -05:00
johnnyq
652edd8ccf Bump TCPDF from 6.10.0 to 6.10.1 2026-01-17 15:13:40 -05:00
johnnyq
6922216d97 Bump stripe-php from 18.1.0 to 19.0.0 2026-01-17 15:13:40 -05:00
johnnyq
17da8f88aa Remove library phpMimeParser as its no longer needed and php-imap webklex is not doing this function 2026-01-17 15:13:40 -05:00
johnnyq
d52e5567fd Bump PHPMailer from 7.0.0 to 7.0.1 2026-01-17 15:13:39 -05:00
johnnyq
8d94a08ffd remove folder location vars as no longer needed as files and documents have been merged 2026-01-17 15:13:39 -05:00
johnnyq
35ba1b2bab Migrate Invoice to Recurring Invoice to an ajax modal 2026-01-17 15:13:39 -05:00
johnnyq
071c91702a Convert Quote to Invoice to use ajax-modal 2026-01-17 15:13:39 -05:00
johnnyq
941ed96d23 Fix dupe race condition with ticket, invoice, quote, project, recurring ticket numbering when being created in parallel Atomically update and get the next ticket number in one SQL query everywhere. 2026-01-17 15:13:38 -05:00
johnnyq
d6591ad85d Fix dupe ticket numbering when being created in parallel Atomically update and get the next ticket number in one SQL query. 2026-01-17 15:13:38 -05:00
johnnyq
02ab62f4d4 Conver the what should be the last bulk asset interfaces modals to the new ajax 2026-01-17 15:13:38 -05:00
johnnyq
e5dd1d80fb Convert Bulk Edit Product Category modal to ajax 2026-01-17 15:13:38 -05:00
johnnyq
3c074fec30 Convert Bulk Edit Product Category modal to ajax 2026-01-17 15:13:38 -05:00
johnnyq
07d69b8436 Convert Document from Template modal to ajax 2026-01-17 15:13:38 -05:00
johnnyq
d43e7ded81 Updated bulk action js to pass the checkboxe names into the get array this allows the use of multiple checkbox name arrays to be passed at once instead of just selected_ids had to update each bulk model from selected_ids to to the array that was passed. This was important so we could mix files and documents together 2026-01-17 15:13:37 -05:00
wrongecho
861dc65f9c Invoices - Allow specifying discount during creation 2026-01-17 15:13:37 -05:00
johnnyq
ae6628684e Update Bulk Action JS to accept and pass multiple custom name selector arrays but default to selected_ids if data-bulk-names is not specified 2026-01-17 15:13:37 -05:00
johnnyq
1e5f76139c Fix Decimal not showing on the iphone for specific fields associated to price cost percentage etc 2026-01-17 15:13:35 -05:00
johnnyq
cd9da33de1 Create upload folders for recurring tickets and ticket_templates 2026-01-17 15:13:35 -05:00
johnnyq
9c28ee4bf1 Add back deleted client edit in post 2026-01-17 15:13:35 -05:00
johnnyq
3eeb5c5bc3 Process base64 Images for document creation and editing for the API and Client Portal 2026-01-17 15:13:35 -05:00
johnnyq
7ff68d207c Introduce cleanupUnusedImages function to delete referenced files that have been deleted when editing content which as been added to document template edit. Did not do this for documents as they are versioned and images will remain until the document is fully deleted 2026-01-17 15:13:35 -05:00
johnnyq
941b589a88 Add function copyDirectory so when creating a document from a template copy the document_template folder to documents folder and update links 2026-01-17 15:13:35 -05:00
johnnyq
39e4722635 Update add and edit Document template to extract base64 images and place them into files instead also delete the document_template/document_template_id folder when deleting a document template 2026-01-17 15:13:35 -05:00
johnnyq
130fcefe04 Remove all side nav Quick adds 2026-01-17 15:13:34 -05:00
johnnyq
e0b0919cf6 Add custom folder to uploads for custom uploading for custom modules 2026-01-17 15:13:34 -05:00
johnnyq
b0d452515a Add Document Templates to uploads dir 2026-01-17 15:13:34 -05:00
johnnyq
fc4f661817 Focus on Author and Date values 2026-01-17 15:13:34 -05:00
johnnyq
054c069c5b Fix up UI on document details header 2026-01-17 15:13:34 -05:00
johnnyq
84ee380808 Cleanup UI for document details title header 2026-01-17 15:13:34 -05:00
johnnyq
8013cf09be Also Delete Documents/Document_id folder during bulk delete 2026-01-17 15:13:34 -05:00
johnnyq
8478a3f12f use saveBase64Image function for edit document as well and when document is deleted, delete the corresponding folder uploads/documents/document_id 2026-01-17 15:13:34 -05:00
johnnyq
37680e5f07 Add Exclude uploads/documents to gitignore 2026-01-17 15:13:34 -05:00
johnnyq
423584177e Implemented saveBase64Images() to convert base64 <img> tags into real files stored under /uploads/<module>/<id>/ with secure filenames. Added wrapper functions and updated document creation to use processed image paths. 2026-01-17 15:13:34 -05:00
johnnyq
c0a43eead1 Fix 'Email from at' On tickets that come from emails, was cuasing dup html head body tags causing htmlPurifier to strip it in ticket viewing, so we removed html body and head tags also remove orginal reply on reply ticket emails this removed ##- Please type your reply above this line -## and anything after it. Also removed the custom CSS that was embedded for all email sent out from ITFlow 2026-01-17 15:13:33 -05:00
johnnyq
de79ffd87c Update Add Client to use prepared statments 2026-01-17 15:13:33 -05:00
johnnyq
e00eb305dc Add cleanInput function without mysqli_escape_string and converted add and edit payment method to Procedural mysqli Prepared Statments 2026-01-17 15:13:33 -05:00
johnnyq
aa03579b58 Fix Bulk Ticket Merging due to missing modal footer 2026-01-17 15:13:33 -05:00
johnnyq
0ed674103e Remove Duplicate get_query_strings code as this is all handled in the the filter header 2026-01-17 15:13:32 -05:00
johnnyq
bee9b64af3 Fix Broken Updating asset noted in asset details modal 2026-01-17 15:13:32 -05:00
wrongecho
d1cb20150b Introduce subject-based automatic ticket merging/reply detection where e-mail is sent from a known contact or domain and the subject is a 95% match for a ticket opened in the last 7 days for that client 2026-01-17 15:13:32 -05:00
johnnyq
b9aafd401f Fix Broken Links in Email to Agent via Client Portal Ticket Update, update changelog 2026-01-17 15:13:32 -05:00
johnnyq
cae99787ba Update Changelog 2026-01-17 15:13:32 -05:00
johnnyq
17ee189313 Update Ticket Detail card to use the adminlte's Card Collapse 2026-01-17 15:13:32 -05:00
johnnyq
be3464fc03 Update Test IMAP to use a Raw connection instead of depending on the Deprecated php-imap extension 2026-01-17 15:13:32 -05:00
johnnyq
dae12184d1 Use btn-tool for side references in Ticket details and some cleanup 2026-01-17 15:13:31 -05:00
johnnyq
95fa86db77 Move Ticket edit from top Right Menu to Ticket Details Section 2026-01-17 15:13:31 -05:00
johnnyq
b4531ef02a Update Changelog 2026-01-17 15:13:31 -05:00
johnnyq
c940c319ce Ticket Details Checks, Dont display Add/edit relations if no cliet in selected, dont show relations in ticket edit if no client assigned to ticket, also dont display public and email response type if no contact_email exists 2026-01-17 15:13:31 -05:00
johnnyq
cd828c07cf Dont show Client Tickets in Ticket Details Breadcrumbs if not client is assigned a ticket 2026-01-17 15:13:31 -05:00
johnnyq
0a8e44b145 Add Tag Displays in edit and listing, remove unused type column 2026-01-17 15:13:31 -05:00
johnnyq
bcd87b57d8 Added Tag Type Filter Nav to tags 2026-01-17 15:13:30 -05:00
johnnyq
7d87ceb877 Hide contract side nav as its not yet complete 2026-01-17 15:13:30 -05:00
johnnyq
b551a63865 Update Changelog and bunp App Version 2026-01-17 15:13:30 -05:00
johnnyq
8a48548ca1 Fix regression in dashboard has client 2026-01-17 15:13:30 -05:00
johnnyq
470d217d25 Fix Pay With a Saved Card in Invoice Listing if Saved Cards are on files for that client 2026-01-17 15:13:30 -05:00
johnnyq
6f453183bd Update Wording on delete provider 2026-01-17 15:13:30 -05:00
johnnyq
1ee7f18d35 Add Back Delete Payment Provider, the db will cascade delete all related recurring payments, related saved cards and client payment provider relation 2026-01-17 15:13:30 -05:00
johnnyq
953d374962 Composer updates 2026-01-17 15:13:30 -05:00
johnnyq
05e13917fc Updated symfony/http-foundation from 7.3.3 to 7.3.7 2026-01-17 15:13:29 -05:00
johnnyq
fcd4a0139b Add Where clause to only accept saved payment by logged in session_client_id in Client Portal 2026-01-17 15:13:29 -05:00
johnnyq
2466c6b99e Add TOTP Secret to Export / Offboard Client Documentation PDF 2026-01-17 15:13:29 -05:00
johnnyq
3e62fc8118 Afer Ticket Merge Redirect to new ticket Details 2026-01-17 15:13:29 -05:00
johnnyq
6112ac0e6e Add UserID: on hover in users 2026-01-17 15:13:29 -05:00
johnnyq
7ea0a2fdb8 If ticket doesn't have a client dont show client section 2026-01-17 15:13:29 -05:00
johnnyq
c5a329c443 Fix Add Ticket Watcher 2026-01-17 15:13:29 -05:00
johnnyq
69934b3ae5 Migrate Ticket Template add to ajax-modal, add category type option if not defined, add product type if not defined 2026-01-17 15:13:29 -05:00
johnnyq
111bbca053 Added Quick Add Links to the majority of Side bars navs 2026-01-17 15:13:28 -05:00
johnnyq
5989aee602 Fix Mail Queue link when sending a test email, updated the quote send email wording to Quote sent 2026-01-17 15:13:28 -05:00
johnnyq
d322223ba7 Fix unable to delete Vendor Templates 2026-01-17 15:13:28 -05:00
johnnyq
0f6b120d84 Add Asset Tags Display in Contact Details, asset details, along with their detail modals 2026-01-17 15:13:27 -05:00
johnnyq
0f2edbe982 [Feature] Added Asset Tags 2026-01-17 15:13:27 -05:00
johnnyq
a5ae345d9e Fix broken edit payment methods due to missing hidden field 2026-01-17 15:13:26 -05:00
e7be82a533 Merge branch 'main' into stage 2026-01-17 20:10:07 +00:00
54ebb39f6e workflows that wont work for us ;) 2026-01-17 15:09:38 -05:00
1c95c576fc comment out htaccess setting that does not work on synology
Some checks failed
SQL Syntax Check for db.sql / Check db.sql SQL Syntax (pull_request) Failing after 28s
PHPLint / build (pull_request) Successful in 16s
Welcome New Contributor / run (pull_request_target) Successful in 17s
2026-01-17 15:00:40 -05:00
526bea6eb4 fix permissions on cron 2025-11-10 09:49:58 -05:00
dd92bef63c prod to stage
# Conflicts:
#	includes/filter_header.php
#	scripts/cron.php
#	scripts/cron_certificate_refresher.php
#	scripts/cron_domain_refresher.php
#	scripts/cron_mail_queue.php
#	scripts/cron_ticket_email_parser.php
2025-11-10 09:32:02 -05:00
Johnny
d1dcc5fb7e Merge pull request #1246 from itflow-org/develop
Develop to Master for Release
2025-11-08 13:47:43 -05:00
johnnyq
9f19fd3c75 Fix Folder in Document API End point 2025-11-08 13:10:35 -05:00
johnnyq
61dedb7e7b Removed old Cron Files from /scripts/ removed old sendmail function along with PHPMailer requirments in functions.php, removed debug php ext check for php-mime-mail-parser and php-imap 2025-11-08 12:56:16 -05:00
johnnyq
65d2b8b2cb UJpdate App Version and Changelog for release 2025-11-08 12:44:58 -05:00
johnnyq
1d3f206660 Addec Contract Templates Listing add modal and add post code 2025-11-07 17:55:19 -05:00
johnnyq
ab46899e72 [FEATURE] Client Contracts, initial DB Schema, rates and net terms along with SLA Reponse / Resolution times will eventually be moved over to this 2025-11-07 16:49:35 -05:00
johnnyq
723a423b06 After ticket Creation Redirect to ticket details with Client Side bar and Top bar, Remove Currency code from Client Add / Edit defaults to company currency for now 2025-11-07 14:27:22 -05:00
johnnyq
a837b97870 Migrated the last of the bulk modals to the new ajax-modal 2025-11-06 22:49:44 -05:00
johnnyq
8be0789f25 Converted even more bulk modals to the new ajax-modal 2025-11-06 20:36:30 -05:00
wrongecho
99d017144d Merge branch 'develop' of https://github.com/itflow-org/itflow into develop 2025-11-06 16:58:35 +00:00
wrongecho
891f71006b Mail queue - Recipient domain MX validation before sending 2025-11-06 16:58:18 +00:00
wrongecho
d25017216a substr to conform to db columns for logs 2025-11-06 16:57:14 +00:00
wrongecho
83b7c7b054 substr to conform to db columns 2025-11-06 16:49:14 +00:00
wrongecho
283c2a17df sanitize after substr 2025-11-06 16:44:34 +00:00
johnnyq
44de049f3b Remove image optimization on upload for now as this will later be added a cron task 2025-11-06 11:44:22 -05:00
wrongecho
920d08f039 Note 2025-11-06 16:27:46 +00:00
johnnyq
0cf1e338c2 Added data-bulk to the ajax modal to allow for bulk GET collection of selected ids that have a class of bulk-select, converted expense and client bulk modals to use the the new ajax-modal 2025-11-06 11:26:08 -05:00
wrongecho
293a2b800e Merge pull request #1244 from Flos/fix-timer-sleeping-chrome-tab-and-initialise-on-reload
Fix ticket timer, to initialise on reload and after tab sleeping
2025-11-06 16:18:46 +00:00
wrongecho
650a099e19 Contacts API - Prevent more than 1 primary contact being set per client 2025-11-06 16:00:21 +00:00
wrongecho
46c2c8616e Clients API - Add - abbreviation support 2025-11-06 15:35:43 +00:00
wrongecho
6295a5c878 Clients API - Update endpoint 2025-11-06 15:34:19 +00:00
wrongecho
39d8e19e16 Clients API - Archiving & Un-archiving 2025-11-06 15:21:45 +00:00
wrongecho
9d3a44d110 Contacts API - Archiving & Un-archiving 2025-11-06 15:10:25 +00:00
wrongecho
54d46719c2 Certificates API - Create endpoint 2025-11-06 14:46:08 +00:00
wrongecho
dbed2c17db Certificates - Bugfix missing js to fetch details 2025-11-06 14:44:24 +00:00
wrongecho
f772ef2efd Certificates - Better empty date handling in agent ui 2025-11-06 14:44:03 +00:00
wrongecho
2f28f96f8d Log the API endpoint/URL path for API auth failures to assist with debugging 2025-11-06 14:43:32 +00:00
wrongecho
1f2bcf7c34 Domains - show a dash instead of blank where there is no expiry 2025-11-06 12:29:07 +00:00
wrongecho
a9a5850fd4 Domains - only show time to expire when there is an expiry date set (otherwise it shows epoch 56 years ago) 2025-11-06 12:19:28 +00:00
wrongecho
09f3bfd8f4 When fetching domain records, quit if no SOA record exists (prevents most sub-domains) 2025-11-06 11:57:08 +00:00
wrongecho
3813fbf8f2 When adding a domain, flag if no SOA record exists (prevents most sub-domains) 2025-11-06 10:41:52 +00:00
wrongecho
16001f8d4e When adding a contact, flag duplicate or invalid e-mail addresses 2025-11-05 22:22:28 +00:00
wrongecho
49d3dbad9a Fix client delete 2025-11-05 10:24:39 +00:00
johnnyq
56f32a4da2 Finished migrating the last of the admin add modals to ajax-modal 2025-11-05 01:54:49 -05:00
johnnyq
a297b8d6d8 Migrate many admin Add modals to the new ajax-modal 2025-11-05 01:39:22 -05:00
johnnyq
d365f48192 Minor ticket details sprucing little more padding on top ticket details and move subject to top with Ticket number 2025-11-04 19:25:07 -05:00
johnnyq
df6d955261 Migrate Schedule Ticket and Merge Ticket to ajax modal also spruce up Schedule Inteface and cleanup code 2025-11-04 18:37:43 -05:00
johnnyq
9fcaf9f5cc [Feature] Updated Invoice Ticket to include more details in the description, predefined along with optional Invoice Title, helper texts below qty and price to show how it gets its information, fixed ticket number not showing in ticket reply when adding ticket to an existing invoice. Add to Existing Invoice is default if open invoices exist, migrated many more ticket related modals to use ajax-modal 2025-11-04 17:48:21 -05:00
johnnyq
43a7b7faa5 [Feature] Allow searching quote via Global Search 2025-11-03 17:08:55 -05:00
johnnyq
69253385c5 Update Invoice, Quote, Recurring Invoice Hyperlinks to take you directly to the client view instead of keeping you in global view. We also did this with tickets in the previous commit 2025-11-03 16:29:41 -05:00
johnnyq
cea7d61481 Updated Bread crumbs in ticket, quote invoice to show All as the first breadcrumb 2025-11-03 15:43:56 -05:00
johnnyq
41f9a2e6e2 Migrated add revenue, trip, quote, invoice, recurring invoice, product, document, folder, file, project, and asset interface over to the new ajax-modal 2025-11-03 14:06:44 -05:00
johnnyq
31d3659098 Migrated product add to the new ajax-modal 2025-11-02 23:20:42 -05:00
johnnyq
c12bfb157e Migrate Add Ticket, Recurring Ticket, Project and Vendor to the new ajax-modal 2025-11-02 22:54:48 -05:00
johnnyq
a55dabb1cd Migrate credemtial, software, network, certificate, domain, service Add modals to the new ajax-modal 2025-11-02 19:39:34 -05:00
johnnyq
06fec3c280 Migrate add locaiton to new ajax-modal 2025-11-02 18:07:39 -05:00
johnnyq
f733a27ad7 Bump DataTable from 2.3.3 to 2.3.4, TinyMCE 8.0.2 to 8.2.0, Stripe-PHP 17.6.0 to 18.1.0, PHPMailer from 6.10.0 to 7.0.0, chartjs from 4.5.0 to 4.5.1 2025-11-02 16:44:59 -05:00
johnnyq
7ea39eb545 Fix non existent record in contact details, document details, document template, ticket template also add limit 1 2025-11-02 13:32:44 -05:00
johnnyq
a85f898ef5 Fix No records exist if client_id in the uri is non existent 2025-11-02 13:13:51 -05:00
johnnyq
519975f3cf Fix Include footer link in project details when no record exists 2025-11-02 12:49:24 -05:00
Johnny
0e9a071e96 Merge pull request #1245 from itflow-org/undefined-asset-handling
Better error handling for undefined/non-existent asset IDs
2025-11-02 12:42:25 -05:00
wrongecho
3917e66fd8 Better error handling for undefined/non-existent asset IDs 2025-11-02 17:17:37 +00:00
wrongecho
9f48e2d9f0 Better error handling for undefined/non-existent asset IDs 2025-11-02 17:14:01 +00:00
wrongecho
215eadcf2b Better error handling for undefined/non-existent asset IDs 2025-11-02 17:12:03 +00:00
Flos
b09e4938b7 Fix ticket timer, to initialise on reload and after tab sleeping
When the tab was reloaded, the timer was not initialized again.
When the tab was in background and the tab was sleeping, the timer showed the wrong time
2025-11-01 23:23:25 +01:00
johnnyq
d3d706ea68 Added ticket details to the search query in global search tickets 2025-11-01 16:28:23 -04:00
johnnyq
8268761ef4 Add Recurring Invoice Reference along with a link in Invoices 2025-11-01 16:17:11 -04:00
wrongecho
2850c35bdc Flag duplicate clients/leads when using the client_add modal 2025-11-01 18:48:23 +00:00
wrongecho
24d8635dac Invoice product autocomplete - search product code as well as name 2025-11-01 17:59:12 +00:00
johnnyq
8314a115bb Migrate Add Asset to the new ajax-modal 2025-10-30 19:05:37 -04:00
johnnyq
b8e2423dbd Mugrated Payment Modals from invoice folder to payment modal folder 2025-10-30 14:46:49 -04:00
johnnyq
52c67f4139 Remove unused budget code 2025-10-30 14:29:51 -04:00
johnnyq
e895156d03 Fix TinyMCE not working on bulk create tickets and sort Categories ASC and fix assign to 2025-10-30 14:06:09 -04:00
johnnyq
89abc18465 Migrated Contact Add to the ajax-modal 2025-10-30 13:58:10 -04:00
johnnyq
355dfbbb25 [Feature] Create Recurring Ticket - Add Asset Type Optgroups on asset selection along with make, model and assigned contact 2025-10-29 19:14:21 -04:00
johnnyq
6d15640ae4 [Feature] Recurring Ticket - Add Three Day and Biweekly to the Frequency options 2025-10-29 18:15:21 -04:00
johnnyq
ad4ab5a54c Fix in old add ticket 2025-10-29 17:50:37 -04:00
johnnyq
3c5c86c4c5 Fix Issue with user not showing up in add ticket and recurring ticket, Also fixed the sort from DESC to ASC in some areas with user select 2025-10-29 17:49:39 -04:00
johnnyq
09b91c8826 [Feature] Recurring Tickets - Add Category, Assigned Agent and Billable Status filters 2025-10-29 17:13:52 -04:00
johnnyq
13ea48bff8 Seperate out recurring expenses and expenses into their own post file 2025-10-29 16:21:56 -04:00
johnnyq
26bb430d6e Seperate out posts into payment, invoice and recurring invoice instead of them all being under invoice post file 2025-10-29 16:18:32 -04:00
johnnyq
82da54740f Moved recurring ticket posts to its own post file 2025-10-29 15:58:04 -04:00
johnnyq
e02b10d12a [Feature] Added Billable column in recurring ticket list view along with bulk actions to set priority, agent, billable status, category and next run date 2025-10-29 15:51:14 -04:00
johnnyq
1573045157 Sort recurring tickets by Next Run Date instead of subject, and Swap Client column with Netrun column so Client column is last and next run date is first 2025-10-29 12:25:02 -04:00
johnnyq
bf31c333a6 Migrate Add Client Modal to the new Ajax Modal 2025-10-28 16:56:27 -04:00
johnnyq
4229bca978 Major UI Work on Contact Details Modal Always Display common details at the top with the nav underneath. 2025-10-25 18:16:56 -04:00
johnnyq
13bd929755 Tidy up the contact details modal 2025-10-25 14:44:20 -04:00
johnnyq
7f6c0346af Add https:// prefix to vendor website field in vendor details modal 2025-10-25 13:09:25 -04:00
johnnyq
0387e66066 Added Sortable Task Count in Ticket Templates Listing view 2025-10-25 12:54:58 -04:00
johnnyq
04bae8dc37 Add Archive and Delete buttons to document details along with button titles to state what the button does, also added a from var to fix redirect behavior if deleting from document details go back to documents listing 2025-10-24 14:46:09 -04:00
johnnyq
559506fc90 Added Access Modules to view current modules and to allow custom modules for the future for use in custom code directories 2025-10-23 15:55:54 -04:00
johnnyq
f2b6d481a1 Feature: Add new date range picker to admin area mail queue audit log, app log 2025-10-23 13:30:22 -04:00
johnnyq
c66aa92365 Update All Side Nav Links to be absolute so the side bar includes can be navigatable when navs are included in custom code 2025-10-23 13:07:02 -04:00
johnnyq
e24ef68d8d Fix Deleting Recurring Ticket from asset details page due to missing CSRF Check token 2025-10-22 17:11:26 -04:00
johnnyq
0cacf83ae5 Fix Sending Email when Forcing a Recurring Invoice into an Invoice 2025-10-22 16:28:53 -04:00
johnnyq
2dc66b329b Fix Ajax Modal Link to referral category in Add Bulk Referral 2025-10-22 15:26:15 -04:00
johnnyq
10dc8ea2bf Wording update for client bulk modals 2025-10-22 14:53:43 -04:00
johnnyq
303f9174c9 Added Bulk Create Tickets for Clients 2025-10-22 14:50:50 -04:00
johnnyq
c5dd5f2b6f Add Clause to not collapse advanced filter on all time aka if date from is set to the default 1970-01-01 2025-10-20 18:16:39 -04:00
johnnyq
ab77705ca2 Feature: Replace old date range to Date Range Picker JS for better date from/to handling 2025-10-20 18:04:00 -04:00
johnnyq
10c89ebf73 Merge branch 'develop' of github.com:itflow-org/itflow into develop 2025-10-16 11:43:37 -04:00
johnnyq
ecce994921 Used status var unstead of get status var for checkall 2025-10-16 11:43:26 -04:00
wrongecho
5dd4f5ea62 New mail parser:
- bugfix .eml not being generated
- include the message when notifying the tech of a reply
2025-10-16 16:32:37 +01:00
wrongecho
93bb5db019 typo 2025-10-15 21:56:21 +01:00
wrongecho
65ff008ccf Bugfix - Email not including ticket guest key 2025-10-15 15:36:07 +01:00
wrongecho
f0c48d23fe Add html code plugin + button to tinymceticket 2025-10-15 15:27:56 +01:00
wrongecho
975b52a43d Time tracking - show H/M/S placeholders if timer auto-start is disabled 2025-10-15 12:29:26 +01:00
wrongecho
079b0d5024 Asset import - allow importing notes 2025-10-15 10:32:16 +01:00
wrongecho
99ccb12b8c Allow importing TOTP credential info 2025-10-15 10:31:59 +01:00
wrongecho
0bb7d24e07 Allow importing TOTP credential info 2025-10-15 10:18:44 +01:00
wrongecho
b7a9f9ea38 When exporting credential info, include the TOTP secret 2025-10-15 10:12:14 +01:00
wrongecho
21aee98f9f Fix checkAll ticket box not showing when status wasn't set - should only be hidden for the closed view 2025-10-15 09:57:32 +01:00
wrongecho
9a5a4be64a When archiving a client, cancel recurring invoices 2025-10-15 09:20:08 +01:00
wrongecho
db7f8501d0 When archiving a client, cancel recurring invoices 2025-10-15 09:18:53 +01:00
johnnyq
61d15cbf9e Remove non existent seatch column recurring ticket prefix 2025-10-14 16:07:08 -04:00
johnnyq
39c9c695f1 Allow searching tickets with ticketprefix and number combo in Global search 2025-10-14 15:59:29 -04:00
johnnyq
d97654581b Add 30 Day wording to Expiring Domain and Certificates in dashboard 2025-10-12 13:34:27 -04:00
johnnyq
2ee70fd3a8 Update .htaccess 2025-10-09 19:23:48 -04:00
johnnyq
b336ec4188 Revert setup restore to a saner version 2025-10-09 19:14:31 -04:00
johnnyq
c77e1be1c3 Try to fix uploads 2025-10-09 19:00:02 -04:00
johnnyq
986f688468 another Attempt at restore 2025-10-09 18:49:54 -04:00
johnnyq
1d9429b762 Another attempt at restore 2025-10-09 18:27:35 -04:00
johnnyq
d122d90a47 Remove CSRF check 2025-10-09 18:11:16 -04:00
johnnyq
2c534d4d20 Attempt to fix uploads and writing to config file during setup 2025-10-09 18:10:21 -04:00
johnnyq
b7e0e5c5eb Fix setup complete flag 2025-10-09 13:00:00 -04:00
johnnyq
2915b12181 Remove temp CSRF check on setup 2025-10-09 12:43:28 -04:00
johnnyq
ed589ef65b Update Backup / Restore, now streams backup and restore to disk instead of memory causing memory to run out, sets timeout limit to unlimited, checks backup file contents for anything bad, use php instead shell exec for import of db, added .htaccess for apache to prevent php execution in /uploads/ directory as this is intended for file download only 2025-10-09 12:28:38 -04:00
569 changed files with 28958 additions and 25009 deletions

View File

@@ -1,37 +0,0 @@
name: SQL Syntax Check for db.sql
on:
pull_request:
paths:
- 'db.sql'
jobs:
syntax_check:
name: Check db.sql SQL Syntax
runs-on: ubuntu-latest
services:
mariadb:
image: mariadb:latest
ports:
- "3306:3306"
env:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MARIADB_USER: user
MARIADB_PASSWORD: password
MARIADB_DATABASE: itfsyntaxdb
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Import & Lint db.sql
run: mysql --host 127.0.0.1 -uuser -ppassword itfsyntaxdb < db.sql
- name: Show imported tables
run: mysql --host 127.0.0.1 -uuser -ppassword itfsyntaxdb -e "show tables;"

View File

@@ -1,29 +0,0 @@
name: Welcome New Contributor
on:
issues:
types: [opened]
pull_request_target:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1.2.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: |
Hello & Welcome! :)
Thanks for taking the time to get in touch.
We ask that all bugs/feature/support requests are raised via the [forum](https://forum.itflow.org). We'll be in touch shortly to confirm.
pr-message: |
Hello & Welcome! :)
Thanks for taking the time to help improve ITFlow. We're excited to review your contributions - we'll review this PR as soon as we can!
Whilst you're waiting, please feel free to check out the [forum](https://forum.itflow.org).
Just so you know, all contributions to ITFlow are licensed under the GNU GPL. By contributing you grant us a perpetual & irrevocable license to include your work in ITFlow.

View File

@@ -1,15 +0,0 @@
name: PHPLint
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Check PHP syntax errors
uses: overtrue/phplint@9.4.1

10
.gitignore vendored
View File

@@ -4,8 +4,16 @@ config.php
uploads/favicon.ico
uploads/clients/*
!uploads/clients/index.php
uploads/custom/*
!uploads/custom/index.php
uploads/documents/*
!uploads/documents/index.php
uploads/document_templates/*
!uploads/document_templates/index.php
uploads/expenses/*
!uploads/expenses/index.php
uploads/recurring_tickets/*
!uploads/recurring_tickets/index.php
uploads/settings/*
!uploads/settings/index.php
uploads/users/*
@@ -14,6 +22,8 @@ uploads/tmp/*
!uploads/tmp/index.php
uploads/tickets/*
!uploads/tickets/index.php
uploads/ticket_templates/*
!uploads/ticket_templates/index.php
.idea/*
plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/*
!plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/.gitkeep

View File

@@ -2,6 +2,180 @@
This file documents all notable changes made to ITFlow.
## [25.12.1] Maint Release
### Major Changes
- Unified the Client/Agent Login and process (Note only Client Users can Reset passwords from the login page, does not apply to agent users).
### Bug Fixes
- Fix Payment Provider not adding an account.
- Fix New ticket button in contact details in the related tickets section.
### New Features & Updates
- You can now Set Payment Provider income/expense account, expense vendor and expense category upond creation or editing.
- Moved Saved Payment Provider Methods away from admin side nav to the count link within Payment Providers page.
- Moved AI Models from the admin side nav to the model count link within AI Providers.
- Add Favicon Reset.
## [25.12] Stable Release
### Breaking Changes ###
- For Existing installs: **php-xml** extension needs to be installed for document creation and editing, new install script does this for you as of Dec 6th 2025. To install php-xml: `sudo apt install php-xml`
### Major Changes
- Consolidated "Files" and "Documents" into a single section called **Files**.
### Bug Fixes
- Resolved issue with updating asset notes in asset details.
- Fixed problem with bulk ticket merging.
- Corrected issue where decimal inputs (e.g., price, cost) werent displaying on iPhones in certain forms.
- Added CSV escaping to the sample export data in areas where a sample CSV template is provided.
- Fix a race condition where dupe tickets, invoices, recurring invoices, recurring tickets, quotes will be created using the same number if created in parallel espcecially when using the API.
### New Features & Updates
- Introduced automatic subject-based ticket merging/reply detection. Now, if an email comes from a known contact or domain and the subject matches 95% of a ticket opened in the last 7 days, it will be merged automatically.
- Added `cleanInput` function to sanitize data before inserting it into the database when using MySQLi prepared statements.
- Migrated client post functionality to use MySQLi prepared statements.
- Updated payment method post functionality to use MySQLi prepared statements.
- Implemented `saveBase64Images()` to convert base64-encoded `<img>` tags into actual image files stored under `/uploads/<module>/<id>/` with secure filenames. Added wrapper functions, and updated document creation to use processed image paths.
- For new documents and document templates, images are now stored in `/uploads/documents/$document_id` instead of being stored as base64 in the database, using the `saveBase64Images()` function.
- UI/UX improvements made to the document details page.
- Removed sidebar quick-add options.
- Created new folders in the uploads directory: `documents`, `document_templates`, and `recurring_tickets`.
- Reworked the bulk action function to pass the name arrays, instead of a generic `selected_ids` array. This allows multiple bulk name arrays to be passed at once, currently used for the new file-document merge.
- Big task: Converted the remaining modals to use the new `ajax-modal` system, enabling more flexible flow expansion going forward.
- Mail queue: Added a `--no-mx-validation` flag to bypass recipient domain MX validation.
- Bump PHPMailer from 7.0.0 to 7.0.1.
- Bump stripe-php from 18.1.0 to 19.0.0.
- Bump TCPDF from 6.10.0 to 6.10.1.
- Bump TinyMCE from 8.2.0 to 8.2.2.
## [25.11.1] Maint Release
### Fixes
- Fix broken edit Payment Method.
- Fix unable to delete Vendor Template.
- Fix Mail Queue link in flash alert for testing email and sending a quote.
- Add Show Category Type select if not defined.
- Add Show Product Type select if not defined.
- Fix add ticket watcher.
- Fix if Client isn't assigned to a ticket dont show client view.
- Fix missing session client id check when paying an invoice from client portal.
- Update Composer Webklex-IMAP library dependency symfony/http-foundation from 7.3.3 to 7.3.7 to fix security related issues.
- Add back delete Payment provider the database will handle cascade deletes to saved cards, recurring payments and client payment provider reference.
- Don't show Client Tickets Breadcrumb if no client is assigned to a ticket.
- Don't Show Contact or Assignment Tab in edit ticket if no Client is Assigned.
- Don't Show add contact, asset, vendor, watcher if not client is assigned to a ticket.
- Don't Show Public Comment & Email if contact email doesn't exist.
- Fixed IMAP Test whicn now uses RAW TCP Connection instead of the depracated php-imap extension.
- Fix Broken Link in Ticket Updates via Client Portal to agent.
### Added / Changed
- [Feature] Added Asset Tags.
- [Feature] Added Quick Add Links to most side bar navs example quickly add a client from sidebar.
- Migrate ticket template add to ajax modal.
- Add TOTP secret to Client Export PDF in Credential section.
- Add UserID on hover in users listing.
- Merge ticket now redirects to the new ticket details page.
- [Feature] Add Pay via saved card under invoice Listings.
- Ticket Related Side Items UI Cleanup to use btn-tool class.
## [25.11] Stable
### Deprecation Notice:
- **Outdated CRON Scripts**: The following scripts are removed.
- `/scripts/cron_mail_queue.php`
- `/scripts/cron_ticket_email_parser.php`
- `/scripts/cron.php`
- `/scripts/cron_domain_refresher.php`
- `/scripts/cron_certificate_refresher.php`
**Action Required**: Transition to the new versions:
- `/cron/mail_queue.php`
- `/cron/ticket_email_parser.php`
- `/cron/cron.php`
- `/cron/domain_refresher.php`
- `/cron/certificate_refresher.php`
- PHP Extensions php-imap and php-mime-mail-parser are no longer required.
---
### Fixes
- **Ticket Listing**: Resolved issue where the “Check All” checkbox was visible even when ticket status wasnt set. Now hidden for closed tickets only.
- **Timer Auto-Start**: Show H/M/S placeholders when timer auto-start is disabled.
- **Ticket Guest URL**: Fixed email not including the ticket guest URL key.
- **EML Generation**: Resolved issue with EML not being generated in the new ticket parser.
- **New Ticket Mail Notification**: Included message when notifying the tech of a reply in the new ticket mail parser.
- **Advanced Filter Collapse**: Added clause to prevent collapse of advanced filters when the “from” date is set to the default (1970-01-01).
- **Recurring Invoice**: Fixed issue where email was marked as sent but not actually sent when forcing a recurring invoice to an invoice.
- **CSRF Token**: Fixed issue with deleting recurring ticket from asset details page due to missing CSRF check token.
- **Vendor Website Link**: Fixed missing `https://` prefix in the vendor website link on the vendor details modal.
- **Agent Select Box**: Resolved issue where agents sometimes didnt appear in the agent select boxes.
- **TinyMCE**: Fixed TinyMCE editor issue on Bulk Create Ticket in Assets.
- **Ticket Timer**: Fixed ticket timer initialization after reload and when the tab is put to sleep (background tab).
- **Client Deletion**: Fixed issue with client deletion.
- **Domain Records**: Added flag for missing SOA record when adding a domain (prevents subdomain creation).
- **Domain Fetching**: Quits domain record fetching if no SOA record exists (prevents subdomains).
- **Domain Expiry**: Only show time to expiry when theres an expiry date set; otherwise, display a dash.
- **Certificates**: Improved handling of empty date in the agent UI.
- **Certificates API**: Fixed bug with missing JS to fetch certificate details.
- **API Updates**:
- Clients API: Added support for archiving/un-archiving clients, updating client data, and abbreviation support.
- Contacts API: Added archiving/un-archiving and restriction to only allow one primary contact per client.
- Mail Queue: Added recipient domain MX validation before sending emails.
---
### Added / Changed
- **Backup / Restore**: Improved backup and restore by streaming data to disk (to prevent memory issues), setting unlimited timeouts, checking for bad backup contents, and using PHP for DB import instead of shell exec. Added `.htaccess` to prevent PHP execution in `/uploads/` directory.
- **Ajax Modals**: Migrated all Add and Bulk modals to the new Ajax Modal for improved performance.
- **Recurring Ticket Sorting**: Default sorting of recurring tickets by `RunDate` instead of subject.
- **Recurring Ticket Enhancements**:
- Added Billable column.
- Added bulk actions for setting priority, agent, billable status, and next run dates.
- Added filters for category, assigned agent, and billable status.
- Added new frequency options: 3-day and biweekly.
- **Asset Select**: Updated asset select dropdown to separate asset types using opt groups (planned for wider use).
- **Expiring Domains & Certificates**: Added "30 Day" warning for expiring domains and certificates in the dashboard.
- **Ticket Search**: Allowed search using both ticket prefix and number.
- **Recurring Invoice**: Cancel recurring invoices when the associated client is archived.
- **Credentials Import/Export**: Now includes TOTP secrets when importing/exporting credentials.
- **Asset Notes Import**: Allowed importing of asset notes.
- **Ticket View**: Added a "View HTML Code" button in all ticket views for TinyMCE.
- **Date Range Picker**: Updated all date filters to use the improved DateRangePicker JS.
- **Bulk Ticket Creation**: Added bulk ticket creation for clients.
- **Sidebar Updates**: Updated all sidebars to use absolute paths for easier integration with custom code.
- **Document Actions**: Added Archive and Delete buttons to the Document Details view with improved redirect behavior.
- **Ticket Template Sorting**: Allowed sorting by task count in ticket templates.
- **Contact Modal UI**: Updated contact details modal to display contact information at the top.
- **API & Code Updates**:
- Separated out post files for recurring tickets, invoices, expenses, and payments.
- Removed unused budget code.
- **Invoice Product Autocomplete**: Now allows searching for product codes as well as names.
- **Client Duplicate Check**: Flags duplicate clients or leads when using the client add modal.
- **Recurring Invoice Reference**: Added a column to invoices indicating if they were created from a recurring invoice.
- **Global Search Enhancements**:
- Allowed ticket details to be searchable in global search.
- Allowed searching for quotes in global search.
- **UI/UX Improvements**:
- Spruced up the ticket details page UI.
- Added contact email validation to flag duplicates or invalid addresses.
- **API Debugging**: Log API endpoint/URL path for authentication failures to aid in debugging.
- **Image Upload Optimization**: Removed image optimization from uploads (this will be handled by a cron job in the future).
- **View Behavior Change**: Updated ticket/invoice/quote views to always be in the Client section, showing client-side navigation and top info bar.
---
### Library Updates:
- **DataTable**: Bumped from 2.3.3 to 2.3.4.
- **TinyMCE**: Bumped from 8.0.2 to 8.2.0.
- **Stripe-PHP**: Bumped from 17.6.0 to 18.1.0.
- **PHPMailer**: Bumped from 6.10.0 to 7.0.0.
- **Chart.js**: Bumped from 4.5.0 to 4.5.1.
## [25.10.1]
- Deprecation Notice: `/scripts/cron_mail_queue.php` , `/scripts/cron_ticket_email_parser.php` , `/scripts/cron.php` `/scripts/cron_domain_refresher.php`, `/scripts/cron_certificate_refresher.php` are being phased out. Please transition to `/cron/mail_queue.php` , `/cron/ticket_email_parser.php`, `/cron/cron.php`, `/cron/domain_refresher.php`, `/cron/certificate_refresher.php` These older scripts will be removed in the November 25.11 release—update accordingly. 25.10.1 installs have the script already configured.
@@ -160,7 +334,7 @@ We will provide example code with directory structure for each custom directory
---
### Fixed
- Several security vulnerabilities patched.
- Several security vulnerabilities patched (with thanks to www.helx.io).
- Ticket status is no longer updated when scheduling.
- Client Portal: Tech contacts can no longer edit their own details.
- Fixed overlapping logo issue in Invoice/Quote PDF exports.

View File

@@ -13,7 +13,7 @@ We operate a rolling release model. Any bug fixes will be released into latest v
| Version | Supported |
|---------| ------------------ |
| 25.05 | :white_check_mark: |
| 25.12 | :white_check_mark: |
## Reporting a Vulnerability via GitHub Security Advisories

View File

@@ -12,11 +12,21 @@ $num_rows = mysqli_num_rows($sql);
?>
<ol class="breadcrumb d-print-none">
<li class="breadcrumb-item">
<a href="/admin">Admin</a>
</li>
<li class="breadcrumb-item">
<a href="ai_provider.php">AI Providers</a>
</li>
<li class="breadcrumb-item active">AI Models</li>
</ol>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-robot mr-2"></i>AI Models</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addAIModelModal"><i class="fas fa-plus mr-2"></i>Add Model</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/ai/ai_model_add.php"><i class="fas fa-plus mr-2"></i>Add Model</button>
</div>
</div>
<div class="card-body">
@@ -104,5 +114,4 @@ $num_rows = mysqli_num_rows($sql);
</div>
<?php
require_once "modals/ai/ai_model_add.php";
require_once "../includes/footer.php";

View File

@@ -16,7 +16,7 @@ $num_rows = mysqli_num_rows($sql);
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-robot mr-2"></i>AI Providers</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addAIProviderModal"><i class="fas fa-plus mr-2"></i>Add Provider</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/ai/ai_provider_add.php"><i class="fas fa-plus mr-2"></i>Add Provider</button>
</div>
</div>
<div class="card-body">
@@ -39,7 +39,7 @@ $num_rows = mysqli_num_rows($sql);
Key <?php if ($sort == 'ai_provider_api_key') { echo $order_icon; } ?>
</a>
</th>
<th>
<th class="text-center">
<a class="text-dark">Models</a>
</th>
<th class="text-center">Action</th>
@@ -67,7 +67,8 @@ $num_rows = mysqli_num_rows($sql);
</td>
<td><?php echo $url; ?></td>
<td><?php echo $key; ?></td>
<td><?php echo $ai_model_count; ?></td>
<td class="text-center">
<a class="badge badge-dark badge-pill p-2" href="ai_model.php"><?= $ai_model_count ?></a>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
@@ -105,5 +106,4 @@ $num_rows = mysqli_num_rows($sql);
</div>
<?php
require_once "modals/ai/ai_provider_add.php";
require_once "../includes/footer.php";

View File

@@ -18,159 +18,150 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-key mr-2"></i>API Keys</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addApiKeyModal"><i class="fas fa-plus mr-2"></i>Create</button>
</div>
</div>
<div class="card-body">
<form autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search keys">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<div class="col-md-8">
<div class="btn-group float-right">
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_api_keys">
<i class="fas fa-fw fa-trash mr-2"></i>Revoke
</button>
</div>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'api_key_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_client_id&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'api_key_client_id') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_secret&order=<?php echo $disp; ?>">
Secret <?php if ($sort == 'api_key_secret') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_created_at&order=<?php echo $disp; ?>">
Created <?php if ($sort == 'api_key_created_at') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_expire&order=<?php echo $disp; ?>">
Expires <?php if ($sort == 'api_key_expire') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$api_key_id = intval($row['api_key_id']);
$api_key_name = nullable_htmlentities($row['api_key_name']);
$api_key_secret = nullable_htmlentities("************" . substr($row['api_key_secret'], -4));
$api_key_created_at = nullable_htmlentities($row['api_key_created_at']);
$api_key_expire = nullable_htmlentities($row['api_key_expire']);
if ($api_key_expire < date("Y-m-d H:i:s")) {
$api_key_expire = $api_key_expire . " (Expired)";
}
if ($row['api_key_client_id'] == 0) {
$api_key_client = "<i>All Clients</i>";
} else {
$api_key_client = nullable_htmlentities($row['client_name']);
}
?>
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="api_key_ids[]" value="<?php echo $api_key_id ?>">
</div>
</td>
<td class="text-bold"><?php echo $api_key_name; ?></td>
<td><?php echo $api_key_client; ?></td>
<td><?php echo $api_key_secret; ?></td>
<td><?php echo $api_key_created_at; ?></td>
<td><?php echo $api_key_expire; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_api_key=<?php echo $api_key_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-times mr-2"></i>Revoke
</a>
</div>
</div>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</form>
</div>
<?php require_once "../includes/filter_footer.php";
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-key mr-2"></i>API Keys</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/api/api_key_add.php"><i class="fas fa-plus mr-2"></i>New API Key</button>
</div>
</div>
<script src="../js/bulk_actions.js"></script>
<div class="card-body">
<form autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search keys">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<div class="col-md-8">
<div class="btn-group float-right">
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_api_keys">
<i class="fas fa-fw fa-trash mr-2"></i>Revoke
</button>
</div>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'api_key_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_client_id&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'api_key_client_id') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_secret&order=<?php echo $disp; ?>">
Secret <?php if ($sort == 'api_key_secret') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_created_at&order=<?php echo $disp; ?>">
Created <?php if ($sort == 'api_key_created_at') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=api_key_expire&order=<?php echo $disp; ?>">
Expires <?php if ($sort == 'api_key_expire') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$api_key_id = intval($row['api_key_id']);
$api_key_name = nullable_htmlentities($row['api_key_name']);
$api_key_secret = nullable_htmlentities("************" . substr($row['api_key_secret'], -4));
$api_key_created_at = nullable_htmlentities($row['api_key_created_at']);
$api_key_expire = nullable_htmlentities($row['api_key_expire']);
if ($api_key_expire < date("Y-m-d H:i:s")) {
$api_key_expire = $api_key_expire . " (Expired)";
}
if ($row['api_key_client_id'] == 0) {
$api_key_client = "<i>All Clients</i>";
} else {
$api_key_client = nullable_htmlentities($row['client_name']);
}
?>
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="api_key_ids[]" value="<?php echo $api_key_id ?>">
</div>
</td>
<td class="text-bold"><?php echo $api_key_name; ?></td>
<td><?php echo $api_key_client; ?></td>
<td><?php echo $api_key_secret; ?></td>
<td><?php echo $api_key_created_at; ?></td>
<td><?php echo $api_key_expire; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_api_key=<?php echo $api_key_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-times mr-2"></i>Revoke
</a>
</div>
</div>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</form>
</div>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/api/api_key_add.php";
require_once "../includes/footer.php";

View File

@@ -97,34 +97,15 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
</div>
</div>
<div class="collapse mt-3 <?php if (!empty($_GET['dtf']) || $_GET['canned_date'] !== "custom" ) { echo "show"; } ?>" id="advancedFilter">
<div class="collapse mt-3 <?php if (isset($_GET['dtf']) && $_GET['dtf'] !== '1970-01-01') { echo "show"; } ?>" id="advancedFilter">
<div class="row">
<div class="col-md-2">
<div class="col-md-3">
<div class="form-group">
<label>Canned Date</label>
<select onchange="this.form.submit()" class="form-control select2" name="canned_date">
<option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="">Custom</option>
<option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option>
<option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option>
<option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option>
<option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option>
<option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option>
<option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option>
<option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option>
<option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date From</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date To</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>">
<label>Date range</label>
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
<input type="hidden" name="canned_date" id="canned_date" value="<?php echo nullable_htmlentities($_GET['canned_date']) ?? ''; ?>">
<input type="hidden" name="dtf" id="dtf" value="<?php echo nullable_htmlentities($dtf ?? ''); ?>">
<input type="hidden" name="dtt" id="dtt" value="<?php echo nullable_htmlentities($dtt ?? ''); ?>">
</div>
</div>
</div>

View File

@@ -159,34 +159,15 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
</div>
</div>
<div class="collapse mt-3 <?php if (!empty($_GET['dtf']) || $_GET['canned_date'] !== "custom" ) { echo "show"; } ?>" id="advancedFilter">
<div class="collapse mt-3 <?php if (isset($_GET['dtf']) && $_GET['dtf'] !== '1970-01-01') { echo "show"; } ?>" id="advancedFilter">
<div class="row">
<div class="col-md-2">
<div class="col-md-3">
<div class="form-group">
<label>Canned Date</label>
<select onchange="this.form.submit()" class="form-control select2" name="canned_date">
<option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="">Custom</option>
<option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option>
<option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option>
<option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option>
<option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option>
<option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option>
<option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option>
<option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option>
<option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date From</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date To</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>">
<label>Date range</label>
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
<input type="hidden" name="canned_date" id="canned_date" value="<?php echo nullable_htmlentities($_GET['canned_date']) ?? ''; ?>">
<input type="hidden" name="dtf" id="dtf" value="<?php echo nullable_htmlentities($dtf ?? ''); ?>">
<input type="hidden" name="dtt" id="dtt" value="<?php echo nullable_htmlentities($dtt ?? ''); ?>">
</div>
</div>
</div>

125
admin/contract_template.php Normal file
View File

@@ -0,0 +1,125 @@
<?php
// Default Column Sort by Filter
$sort = "contract_template_name";
$order = "ASC";
require_once "includes/inc_all_admin.php";
// Search query
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM contract_templates
WHERE contract_template_name LIKE '%$q%' OR contract_template_type LIKE '%$q%' OR contract_template_name LIKE '%$q%'
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-file-contract mr-2"></i>Contract Templates</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/contract_template/contract_template_add.php" data-modal-size="lg">
<i class="fas fa-plus mr-2"></i>New Template
</button>
</div>
</div>
<div class="card-body">
<form autocomplete="off">
<div class="input-group">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search templates">
<div class="input-group-append">
<button class="btn btn-secondary"><i class="fa fa-search"></i></button>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<th>Template Name</th>
<th>Type</th>
<th>Update Frequency</th>
<th>SLA (L/M/H Response)</th>
<th>SLA (L/M/H Resolution)</th>
<th>Hourly Rate</th>
<th>After Hours Rate</th>
<th>Support Hours</th>
<th>Net Terms</th>
<th>Created</th>
<th>Updated</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$id = intval($row['contract_template_id']);
$name = nullable_htmlentities($row['contract_template_name']);
$type = nullable_htmlentities($row['contract_template_type']);
$freq = nullable_htmlentities($row['contract_template_update_frequency']);
$sla_low_resp = nullable_htmlentities($row['sla_low_response_time']);
$sla_med_resp = nullable_htmlentities($row['sla_medium_response_time']);
$sla_high_resp = nullable_htmlentities($row['sla_high_response_time']);
$sla_low_res = nullable_htmlentities($row['sla_low_resolution_time']);
$sla_med_res = nullable_htmlentities($row['sla_medium_resolution_time']);
$sla_high_res = nullable_htmlentities($row['sla_high_resolution_time']);
$hourly_rate = nullable_htmlentities($row['contract_template_hourly_rate']);
$after_hours = nullable_htmlentities($row['contract_template_after_hours_hourly_rate']);
$support_hours = nullable_htmlentities($row['contract_template_support_hours']);
$net_terms = nullable_htmlentities($row['contract_template_net_terms']);
$created = nullable_htmlentities($row['contract_template_created_at']);
$updated = nullable_htmlentities($row['contract_template_updated_at']);
?>
<tr>
<td>
<a class="text-bold" href="contract_template_details.php?contract_template_id=<?php echo $id; ?>">
<i class="fas fa-fw fa-file-alt text-dark"></i> <?php echo $name; ?>
</a>
<div class="mt-1 text-secondary"><?php echo nullable_htmlentities($row['contract_template_description']); ?></div>
</td>
<td><?php echo $type; ?></td>
<td><?php echo $freq; ?></td>
<td><?php echo "$sla_low_resp / $sla_med_resp / $sla_high_resp"; ?></td>
<td><?php echo "$sla_low_res / $sla_med_res / $sla_high_res"; ?></td>
<td><?php echo $hourly_rate; ?></td>
<td><?php echo $after_hours; ?></td>
<td><?php echo $support_hours; ?></td>
<td><?php echo $net_terms; ?></td>
<td><?php echo $created; ?></td>
<td><?php echo $updated; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="xl"
data-modal-url="modals/contract_template/contract_template_edit.php?id=<?= $id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="post.php?delete_contract_template=<?php echo $id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
</div>
</div>
</td>
</tr>
<?php } ?>
</tbody>
</table>
<br>
</div>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<?php require_once "../includes/footer.php"; ?>

View File

@@ -21,7 +21,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-external-link-alt mr-2"></i>Custom Links</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addLinkModal"><i class="fas fa-plus mr-2"></i>New Link</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/custom_link/custom_link_add.php"><i class="fas fa-plus mr-2"></i>New Link</button>
</div>
</div>
@@ -145,5 +145,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<?php
require_once "modals/custom_link/custom_link_add.php";
require_once "../includes/footer.php";

View File

@@ -4033,10 +4033,111 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.6'");
}
// if (CURRENT_DATABASE_VERSION == '2.3.5') {
// // Insert queries here required to update to DB version 2.3.5
if (CURRENT_DATABASE_VERSION == '2.3.6') {
// Create New Contract Templates Table
mysqli_query($mysqli, "CREATE TABLE `contract_templates` (
`contract_template_id` INT(11) AUTO_INCREMENT PRIMARY KEY,
`contract_template_name` VARCHAR(255) NOT NULL,
`contract_template_description` TEXT NULL DEFAULT NULL,
`contract_template_type` VARCHAR(50) NULL DEFAULT NULL,
`contract_template_sla_low_response_time` INT(11) NULL DEFAULT NULL,
`contract_template_sla_low_resolution_time` INT(11) NULL DEFAULT NULL,
`contract_template_sla_medium_response_time` INT(11) NULL DEFAULT NULL,
`contract_template_sla_medium_resolution_time` INT(11) NULL DEFAULT NULL,
`contract_template_sla_high_response_time` INT(11) NULL DEFAULT NULL,
`contract_template_sla_high_resolution_time` INT(11) NULL DEFAULT NULL,
`contract_template_rate_standard` DECIMAL(10,2) NULL DEFAULT NULL,
`contract_template_rate_after_hours` DECIMAL(10,2) NULL DEFAULT NULL,
`contract_template_net_terms` VARCHAR(50) NULL DEFAULT NULL,
`contract_template_support_hours` VARCHAR(100) NULL DEFAULT NULL,
`contract_template_renewal_frequency` VARCHAR(50) NULL DEFAULT NULL,
`contract_template_details` TEXT NULL DEFAULT NULL,
`contract_template_created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`contract_template_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
`contract_template_archived_at` DATETIME NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
// Create New Contracts Table
mysqli_query($mysqli, "CREATE TABLE `contracts` (
`contract_id` INT(11) AUTO_INCREMENT PRIMARY KEY,
`contract_name` VARCHAR(255) NOT NULL,
`contract_status` VARCHAR(50) NOT NULL,
`contract_type` VARCHAR(50) NOT NULL,
`contract_sla_low_response_time` INT(11) NULL DEFAULT NULL,
`contract_sla_low_resolution_time` INT(11) NULL DEFAULT NULL,
`contract_sla_medium_response_time` INT(11) NULL DEFAULT NULL,
`contract_sla_medium_resolution_time` INT(11) NULL DEFAULT NULL,
`contract_sla_high_response_time` INT(11) NULL DEFAULT NULL,
`contract_sla_high_resolution_time` INT(11) NULL DEFAULT NULL,
`contract_details` TEXT NULL DEFAULT NULL,
`contract_client_id` INT(11) NULL DEFAULT NULL,
`contract_client_name` VARCHAR(255) NULL DEFAULT NULL,
`contract_client_address` TEXT NULL DEFAULT NULL,
`contract_client_email` VARCHAR(255) NULL DEFAULT NULL,
`contract_client_phone` VARCHAR(100) NULL DEFAULT NULL,
`contract_contact_name` VARCHAR(255) NULL DEFAULT NULL,
`contract_contact_signature` TEXT NULL DEFAULT NULL,
`contract_contact_signature_date` DATETIME NULL DEFAULT NULL,
`contract_agent_name` VARCHAR(255) NULL DEFAULT NULL,
`contract_agent_signature` TEXT NULL DEFAULT NULL,
`contract_agent_signature_date` DATETIME NULL DEFAULT NULL,
`contract_rate_standard` DECIMAL(10,2) NULL DEFAULT NULL,
`contract_rate_after_hours` DECIMAL(10,2) NULL DEFAULT NULL,
`contract_net_terms` VARCHAR(50) NULL DEFAULT NULL,
`contract_support_hours` VARCHAR(100) NULL DEFAULT NULL,
`contract_start_date` DATE NULL DEFAULT NULL,
`contract_end_date` DATE NULL DEFAULT NULL,
`contract_renewal_frequency` VARCHAR(50) NULL DEFAULT NULL,
`contract_created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`contract_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
`contract_archived_at` DATETIME NULL DEFAULT NULL,
FOREIGN KEY (`contract_client_id`) REFERENCES `clients`(`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.7'");
}
if (CURRENT_DATABASE_VERSION == '2.3.7') {
mysqli_query($mysqli, "
CREATE TABLE `asset_tags` (
`asset_tag_asset_id` INT(11) NOT NULL,
`asset_tag_tag_id` INT(11) NOT NULL,
PRIMARY KEY (`asset_tag_asset_id`, `asset_tag_tag_id`),
CONSTRAINT `fk_asset`
FOREIGN KEY (`asset_tag_asset_id`)
REFERENCES `assets`(`asset_id`)
ON DELETE CASCADE,
CONSTRAINT `fk_tag`
FOREIGN KEY (`asset_tag_tag_id`)
REFERENCES `tags`(`tag_id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.8'");
}
// if (CURRENT_DATABASE_VERSION == '2.3.8') {
// // Insert queries here required to update to DB version 2.3.9
// // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.6'");
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.9'");
// }
} else {

View File

@@ -46,14 +46,13 @@ $systemInfo[] = [
// Section: PHP Extensions
$phpExtensions = [];
$extensions = [
'php-mailparse' => 'mailparse',
'php-imap' => 'imap',
'php-mysqli' => 'mysqli',
'php-intl' => 'intl',
'php-curl' => 'curl',
'php-mbstring' => 'mbstring',
'php-gd' => 'gd',
'php-zip' => 'zip',
'php-xml' => 'xml',
];
foreach ($extensions as $name => $ext) {
@@ -684,7 +683,7 @@ $mysqli->close();
</tbody>
</table>
</div>
<!-- Database Structure Comparison Table -->
<h3 class="mt-3">Database Structure Comparison</h3>
@@ -767,4 +766,3 @@ $mysqli->close();
<?php
require_once "../includes/footer.php";

View File

@@ -22,7 +22,7 @@
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-file mr-2"></i>Document Templates</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addDocumentTemplateModal">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/document_template/document_template_add.php" data-modal-size="xl">
<i class="fas fa-plus mr-2"></i>New Template
</button>
</div>
@@ -121,38 +121,4 @@
</div>
</div>
<?php require_once "modals/document_template/document_template_add.php"; ?>
<?php require_once "../includes/footer.php"; ?>
<script>
$(document).ready(function(){
$('#generateAIContent').on('click', function(){
var prompt = $('#aiPrompt').val().trim();
if(prompt === '') {
alert('Please enter a prompt.');
return;
}
$('#generateAIContent').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Generating...');
$.ajax({
url: 'post.php?ai_create_document_template', // The PHP script that calls the OpenAI API
method: 'POST',
data: { prompt: prompt },
dataType: 'html',
success: function(response) {
// Assuming you have exactly one TinyMCE instance on the page
// and it's targeting the .tinymce textarea:
tinymce.activeEditor.setContent(response);
},
error: function() {
alert('Error generating content. Please try again.');
},
complete: function() {
$('#generateAIContent').prop('disabled', false).html('<i class="fa fa-fw fa-magic mr-1"></i>Generate with AI');
}
});
});
});
</script>
<?php require_once "../includes/footer.php";

View File

@@ -15,7 +15,13 @@ if (isset($_GET['document_template_id'])) {
$document_template_id = intval($_GET['document_template_id']);
}
$sql_document = mysqli_query($mysqli, "SELECT * FROM document_templates WHERE document_template_id = $document_template_id");
$sql_document = mysqli_query($mysqli, "SELECT * FROM document_templates WHERE document_template_id = $document_template_id LIMIT 1");
if (mysqli_num_rows($sql_document) == 0) {
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='javascript:history.back()'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
require_once "../includes/footer.php";
exit();
}
$row = mysqli_fetch_array($sql_document);

View File

@@ -14,21 +14,29 @@
<!-- Sidebar Menu -->
<nav>
<ul class="nav nav-pills nav-sidebar flex-column mt-2" data-widget="treeview" data-accordion="false">
<!-- ACCESS Section -->
<li class="nav-header">ACCESS</li>
<li class="nav-item">
<a href="users.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "users.php") {echo "active";} ?>">
<a href="/admin/users.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "users.php") {echo "active";} ?>">
<i class="nav-icon fas fa-users"></i>
<p>Users</p>
</a>
</li>
<li class="nav-item">
<a href="roles.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "roles.php") {echo "active";} ?>">
<a href="/admin/roles.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "roles.php") {echo "active";} ?>">
<i class="nav-icon fas fa-user-shield"></i>
<p>Roles</p>
</a>
</li>
<!-- 2025-12-05 JQ - Hide Permission Modules currently just shows modules
<li class="nav-item">
<a href="api_keys.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "api_keys.php") {echo "active";} ?>">
<a href="/admin/modules.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "modules.php") {echo "active";} ?>">
<i class="nav-icon fas fa-puzzle-piece"></i>
<p>Modules</p>
</a>
</li>
-->
<li class="nav-item">
<a href="/admin/api_keys.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "api_keys.php") {echo "active";} ?>">
<i class="nav-icon fas fa-key"></i>
<p>API Keys</p>
</a>
@@ -36,66 +44,56 @@
<li class="nav-header">TAGS & CATEGORIES</li>
<li class="nav-item">
<a href="tag.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'tag.php' ? 'active' : ''); ?>">
<a href="/admin/tag.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'tag.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-tags"></i>
<p>Tags</p>
</a>
</li>
<li class="nav-item">
<a href="category.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'category.php' ? 'active' : ''); ?>">
<a href="/admin/category.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'category.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-list-ul"></i>
<p>Categories</p>
</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a href="tax.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'tax.php' ? 'active' : ''); ?>">
<a href="/admin/tax.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'tax.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-balance-scale"></i>
<p>Taxes</p>
</a>
</li>
<li class="nav-item">
<a href="payment_method.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'payment_method.php' ? 'active' : ''); ?>">
<a href="/admin/payment_method.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'payment_method.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-hand-holding-usd"></i>
<p>Payment Methods</p>
</a>
</li>
<li class="nav-item">
<a href="payment_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'payment_provider.php' ? 'active' : ''); ?>">
<a href="/admin/payment_provider.php"
class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['payment_provider.php', 'saved_payment_method.php']) ? 'active' : ''); ?>">
<i class="nav-icon far fa-credit-card"></i>
<p>Payment Providers</p>
</a>
</li>
<li class="nav-item">
<a href="saved_payment_method.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'saved_payment_method.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-credit-card"></i>
<p>Saved Payments</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="ai_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'ai_provider.php' ? 'active' : ''); ?>">
<a href="/admin/ai_provider.php"
class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['ai_provider.php', 'ai_model.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-robot"></i>
<p>AI Providers</p>
</a>
</li>
<li class="nav-item">
<a href="ai_model.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'ai_model.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-robot"></i>
<p>AI Models</p>
</a>
</li>
<?php if ($config_module_enable_ticketing) { ?>
<li class="nav-item">
<a href="ticket_status.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'ticket_status.php' ? 'active' : ''); ?>">
<a href="/admin/ticket_status.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'ticket_status.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-info-circle"></i>
<p>Ticket Statuses</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="custom_link.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'custom_link.php' ? 'active' : ''); ?>">
<a href="/admin/custom_link.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'custom_link.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-external-link-alt"></i>
<p>Custom Links</p>
</a>
@@ -104,32 +102,43 @@
<?php if ($config_module_enable_itdoc) { ?>
<li class="nav-header">TEMPLATES</li>
<!-- 2025-11-16 JQ - Hide Contracts not yet ready
<li class="nav-item">
<a href="project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['project_template.php', 'project_template_details.php']) ? 'active' : ''); ?>">
<a href="/admin/contract_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'contract_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file-contract"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/contract_template/contract_template_add.php" data-modal-size="lg"></span>
Contract Templates
</p>
</a>
</li>
-->
<li class="nav-item">
<a href="/admin/project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['project_template.php', 'project_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>Project Templates</p>
</a>
</li>
<li class="nav-item">
<a href="ticket_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['ticket_template.php', 'ticket_template_details.php']) ? 'active' : ''); ?>">
<a href="/admin/ticket_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['ticket_template.php', 'ticket_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Ticket Templates</p>
</a>
</li>
<li class="nav-item">
<a href="vendor_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'vendor_template.php' ? 'active' : ''); ?>">
<a href="/admin/vendor_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'vendor_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-building"></i>
<p>Vendor Templates</p>
</a>
</li>
<li class="nav-item">
<a href="software_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'software_template.php' ? 'active' : ''); ?>">
<a href="/admin/software_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'software_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-rocket"></i>
<p>License Templates</p>
</a>
</li>
<li class="nav-item">
<a href="document_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['document_template.php', 'document_template_details.php']) ? 'active' : ''); ?>">
<a href="/admin/document_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['document_template.php', 'document_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file"></i>
<p>Document Templates</p>
</a>
@@ -139,37 +148,37 @@
<li class="nav-header">MAINTENANCE</li>
<li class="nav-item">
<a href="mail_queue.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'mail_queue.php' ? 'active' : ''); ?>">
<a href="/admin/mail_queue.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'mail_queue.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-mail-bulk"></i>
<p>Mail Queue</p>
</a>
</li>
<li class="nav-item">
<a href="audit_log.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'audit_log.php' ? 'active' : ''); ?>">
<a href="/admin/audit_log.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'audit_log.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-history"></i>
<p>Audit Logs</p>
</a>
</li>
<li class="nav-item">
<a href="app_log.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'app_log.php' ? 'active' : ''); ?>">
<a href="/admin/app_log.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'app_log.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-history"></i>
<p>App Logs</p>
</a>
</li>
<li class="nav-item">
<a href="backup.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'backup.php' ? 'active' : ''); ?>">
<a href="/admin/backup.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'backup.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-cloud-upload-alt"></i>
<p>Backup</p>
</a>
</li>
<li class="nav-item">
<a href="debug.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'debug.php' ? 'active' : ''); ?>">
<a href="/admin/debug.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'debug.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-bug"></i>
<p>Debug</p>
</a>
</li>
<li class="nav-item">
<a href="update.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'update.php' ? 'active' : ''); ?>">
<a href="/admin/update.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'update.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-download"></i>
<p>Update</p>
</a>
@@ -185,56 +194,56 @@
</a>
<ul class="nav nav-treeview">
<li class="nav-item">
<a href="settings_company.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_company.php' ? 'active' : ''); ?>">
<a href="/admin/settings_company.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_company.php' ? 'active' : ''); ?>">
<i class="nav-icon fa fa-briefcase"></i>
<p>Company Details</p>
</a>
</li>
<li class="nav-item">
<a href="settings_localization.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_localization.php' ? 'active' : ''); ?>">
<a href="/admin/settings_localization.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_localization.php' ? 'active' : ''); ?>">
<i class="nav-icon fa fa-globe"></i>
<p>Localization</p>
</a>
</li>
<li class="nav-item">
<a href="settings_theme.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_theme.php' ? 'active' : ''); ?>">
<a href="/admin/settings_theme.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_theme.php' ? 'active' : ''); ?>">
<i class="nav-icon fa fa-paint-brush"></i>
<p>Theme</p>
</a>
</li>
<li class="nav-item">
<a href="settings_security.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_security.php' ? 'active' : ''); ?>">
<a href="/admin/settings_security.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_security.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-shield-alt"></i>
<p>Security</p>
</a>
</li>
<li class="nav-item">
<a href="settings_mail.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_mail.php' ? 'active' : ''); ?>">
<a href="/admin/settings_mail.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_mail.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-envelope"></i>
<p>Mail</p>
</a>
</li>
<li class="nav-item">
<a href="settings_notification.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_notification.php' ? 'active' : ''); ?>">
<a href="/admin/settings_notification.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_notification.php' ? 'active' : ''); ?>">
<i class="nav-icon far fa-bell"></i>
<p>Notifications</p>
</a>
</li>
<li class="nav-item">
<a href="settings_default.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_default.php' ? 'active' : ''); ?>">
<a href="/admin/settings_default.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_default.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-cogs"></i>
<p>Defaults</p>
</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a href="settings_invoice.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_invoice.php' ? 'active' : ''); ?>">
<a href="/admin/settings_invoice.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_invoice.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file-invoice"></i>
<p>Invoice</p>
</a>
</li>
<li class="nav-item">
<a href="settings_quote.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_quote.php' ? 'active' : ''); ?>">
<a href="/admin/settings_quote.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_quote.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-comment-dollar"></i>
<p>Quote</p>
</a>
@@ -242,13 +251,13 @@
<?php } ?>
<?php if ($config_module_enable_ticketing) { ?>
<li class="nav-item">
<a href="settings_project.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_project.php' ? 'active' : ''); ?>">
<a href="/admin/settings_project.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_project.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>Project</p>
</a>
</li>
<li class="nav-item">
<a href="settings_ticket.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_ticket.php' ? 'active' : ''); ?>">
<a href="/admin/settings_ticket.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_ticket.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>Ticket</p>
</a>
@@ -257,20 +266,20 @@
<!-- Currently the only integration is the client portal SSO -->
<?php if ($config_client_portal_enable) { ?>
<li class="nav-item">
<a href="identity_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'identity_provider.php' ? 'active' : ''); ?>">
<a href="/admin/identity_provider.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'identity_provider.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-fingerprint"></i>
<p>Identity Provider</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="settings_telemetry.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_telemetry.php' ? 'active' : ''); ?>">
<a href="/admin/settings_telemetry.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_telemetry.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-satellite-dish"></i>
<p>Telemetry</p>
</a>
</li>
<li class="nav-item">
<a href="settings_module.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_module.php' ? 'active' : ''); ?>">
<a href="/admin/settings_module.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'settings_module.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-cube"></i>
<p>Modules</p>
</a>
@@ -279,7 +288,7 @@
</li>
<?php
$sql_custom_links = mysqli_query($mysqli, "SELECT * FROM custom_links
$sql_custom_links = mysqli_query($mysqli, "SELECT * FROM custom_links
WHERE custom_link_location = 4 AND custom_link_archived_at IS NULL
ORDER BY custom_link_order ASC, custom_link_name ASC"
);

View File

@@ -53,34 +53,15 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
</div>
</div>
<div class="collapse mt-3 <?php if (!empty($_GET['dtf']) || $_GET['canned_date'] !== "custom" ) { echo "show"; } ?>" id="advancedFilter">
<div class="collapse mt-3 <?php if (isset($_GET['dtf']) && $_GET['dtf'] !== '1970-01-01') { echo "show"; } ?>" id="advancedFilter">
<div class="row">
<div class="col-md-2">
<div class="col-md-3">
<div class="form-group">
<label>Canned Date</label>
<select onchange="this.form.submit()" class="form-control select2" name="canned_date">
<option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="">Custom</option>
<option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option>
<option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option>
<option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option>
<option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option>
<option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option>
<option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option>
<option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option>
<option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date From</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date To</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>">
<label>Date range</label>
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
<input type="hidden" name="canned_date" id="canned_date" value="<?php echo nullable_htmlentities($_GET['canned_date']) ?? ''; ?>">
<input type="hidden" name="dtf" id="dtf" value="<?php echo nullable_htmlentities($dtf ?? ''); ?>">
<input type="hidden" name="dtt" id="dtt" value="<?php echo nullable_htmlentities($dtt ?? ''); ?>">
</div>
</div>
</div>

View File

@@ -1,73 +1,77 @@
<div class="form-group">
<div class="modal" id="addAIModelModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-robot mr-2"></i>Add AI Model</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
<?php
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-robot mr-2"></i>Add AI Model</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Provider <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-robot"></i></span>
</div>
<select class="form-control select2" name="provider" required>
<option value="">- Select an AI Provider -</option>
<?php
$sql_ai_providers = mysqli_query($mysqli, "SELECT * FROM ai_providers");
while ($row = mysqli_fetch_array($sql_ai_providers)) {
$ai_provider_id = intval($row['ai_provider_id']);
$ai_provider_name = nullable_htmlentities($row['ai_provider_name']);
?>
<option value="<?php echo $ai_provider_id; ?>"><?php echo $ai_provider_name; ?></option>
<?php } ?>
</select>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Provider <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-robot"></i></span>
</div>
<select class="form-control select2" name="provider" required>
<option value="">- Select an AI Provider -</option>
<?php
$sql_ai_providers = mysqli_query($mysqli, "SELECT * FROM ai_providers");
while ($row = mysqli_fetch_array($sql_ai_providers)) {
$ai_provider_id = intval($row['ai_provider_id']);
$ai_provider_name = nullable_htmlentities($row['ai_provider_name']);
?>
<option value="<?php echo $ai_provider_id; ?>"><?php echo $ai_provider_name; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Model Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-robot"></i></span>
</div>
<input type="text" class="form-control" name="model" placeholder="ex gpt-4">
</div>
</div>
<div class="form-group">
<label>Use Case <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-th-list"></i></span>
</div>
<select class="form-control select2" name="use_case">
<option>General</option>
<option>Tickets</option>
<option>Documentation</option>
</select>
</div>
</div>
<div class="form-group">
<textarea class="form-control" rows="8" name="prompt" placeholder="Enter a model prompt:"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ai_model" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
<div class="form-group">
<label>Model Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-robot"></i></span>
</div>
<input type="text" class="form-control" name="model" placeholder="ex gpt-4">
</div>
</div>
<div class="form-group">
<label>Use Case <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-th-list"></i></span>
</div>
<select class="form-control select2" name="use_case">
<option>General</option>
<option>Tickets</option>
<option>Documentation</option>
</select>
</div>
</div>
<div class="form-group">
<textarea class="form-control" rows="8" name="prompt" placeholder="Enter a model prompt:"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ai_model" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,54 +1,58 @@
<div class="form-group">
<div class="modal" id="addAIProviderModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-robot mr-2"></i>New AI Provider</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<?php
<div class="modal-body">
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Provider Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-robot"></i></span>
</div>
<input type="text" class="form-control" name="provider" placeholder="ex OpenAI">
</div>
</div>
ob_start();
<div class="form-group">
<label>URL <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-globe"></i></span>
</div>
<input type="url" class="form-control" name="url" placeholder="ex https://ai.company.ext/api">
</div>
</div>
?>
<div class="form-group">
<label>API Key</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="api_key" placeholder="Enter API key here">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ai_provider" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-robot mr-2"></i>New AI Provider</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Provider Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-robot"></i></span>
</div>
<input type="text" class="form-control" name="provider" placeholder="ex OpenAI">
</div>
</div>
<div class="form-group">
<label>URL <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-globe"></i></span>
</div>
<input type="url" class="form-control" name="url" placeholder="ex https://ai.company.ext/api">
</div>
</div>
<div class="form-group">
<label>API Key</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="api_key" placeholder="Enter API key here">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ai_provider" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,121 +1,124 @@
<?php
require_once '../../../includes/modal_header.php';
$key = randomString(156);
$decryptPW = randomString(160);
ob_start();
?>
<div class="modal" id="addApiKeyModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-key mr-2"></i>New Key</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-api-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-api-keys">Keys</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-api-details">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="key" value="<?php echo $key ?>">
<input type="hidden" name="password" value="<?php echo $decryptPW ?>">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sticky-note"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Key Name" maxlength="255" required autofocus>
</div>
</div>
<div class="form-group">
<label>Expiration Date <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="date" class="form-control" name="expire" min="<?php echo date('Y-m-d')?>" max="2999-12-31" required>
</div>
</div>
<div class="form-group">
<label>Client Access <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<select class="form-control select2" name="client" required>
<option value="0"> ALL CLIENTS </option>
<?php
$sql = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']); ?>
<option value="<?php echo $client_id; ?>"><?php echo "$client_name (Client ID: $client_id)"; ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-api-keys">
<div class="form-group">
<label>API Key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" value="<?php echo $key ?>" required disabled>
<div class="input-group-append">
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $key; ?>"><i class="fa fa-fw fa-copy"></i></button>
</div>
</div>
</div>
<div class="form-group">
<label>Login credential decryption password <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-unlock-alt"></i></span>
</div>
<input type="text" class="form-control" value="<?php echo $decryptPW ?>" required disabled>
<div class="input-group-append">
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $decryptPW; ?>"><i class="fa fa-fw fa-copy"></i></button>
</div>
</div>
</div>
<br>
<div class="form-group">
<label>I have made a copy of the key(s)<strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<input type="checkbox" name="ack" value="1" required>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_api_key" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-key mr-2"></i>New Key</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-api-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-api-keys">Keys</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-api-details">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="key" value="<?php echo $key ?>">
<input type="hidden" name="password" value="<?php echo $decryptPW ?>">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sticky-note"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Key Name" maxlength="255" required autofocus>
</div>
</div>
<div class="form-group">
<label>Expiration Date <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="date" class="form-control" name="expire" min="<?php echo date('Y-m-d')?>" max="2999-12-31" required>
</div>
</div>
<div class="form-group">
<label>Client Access <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<select class="form-control select2" name="client" required>
<option value="0"> ALL CLIENTS </option>
<?php
$sql = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']); ?>
<option value="<?php echo $client_id; ?>"><?php echo "$client_name (Client ID: $client_id)"; ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-api-keys">
<div class="form-group">
<label>API Key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" value="<?php echo $key ?>" required disabled>
<div class="input-group-append">
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $key; ?>"><i class="fa fa-fw fa-copy"></i></button>
</div>
</div>
</div>
<div class="form-group">
<label>Login credential decryption password <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-unlock-alt"></i></span>
</div>
<input type="text" class="form-control" value="<?php echo $decryptPW ?>" required disabled>
<div class="input-group-append">
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $decryptPW; ?>"><i class="fa fa-fw fa-copy"></i></button>
</div>
</div>
</div>
<br>
<div class="form-group">
<label>I have made a copy of the key(s)<strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<input type="checkbox" name="ack" value="1" required>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_api_key" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -2,7 +2,9 @@
require_once '../../../includes/modal_header.php';
$category = nullable_htmlentities($_GET['category']);
$category = nullable_htmlentities($_GET['category'] ?? '');
$category_types_array = ['Expense', 'Income', 'Referral', 'Ticket'];
?>
@@ -13,10 +15,30 @@ $category = nullable_htmlentities($_GET['category']);
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="type" value="<?php echo ($category); ?>">
<div class="modal-body">
<?php if ($category) { ?>
<input type="hidden" name="type" value="<?= $category ?>">
<?php } else { ?>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Select Type -</option>
<?php foreach ($category_types_array as $type_select) { ?>
<option><?= $type_select ?></option>
<?php } ?>
</select>
</div>
</div>
<?php } ?>
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
@@ -39,7 +61,7 @@ $category = nullable_htmlentities($_GET['category']);
</div>
<div class="modal-footer">
<button type="submit" name="add_category" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="submit" name="add_category" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Category</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>

View File

@@ -0,0 +1,221 @@
<?php
require_once '../../../includes/modal_header.php';
$contract_types_array = ['Fully Managed', 'Partialy Managed', 'Break/Fix'];
$renewal_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '7 Year'];
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-contract mr-2"></i>New Contract Template</h5>
<button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button>
</div>
<!-- Tabs Navigation -->
<ul class="modal-header nav nav-pills nav-justified">
<li class="nav-item">
<a class="nav-link active" id="general-tab" data-toggle="tab" href="#general" role="tab">General Info</a>
</li>
<li class="nav-item">
<a class="nav-link" id="sla-tab" data-toggle="tab" href="#sla" role="tab">SLA</a>
</li>
<li class="nav-item">
<a class="nav-link" id="rates-tab" data-toggle="tab" href="#rates" role="tab">Rates & Support</a>
</li>
<li class="nav-item">
<a class="nav-link" id="details-tab" data-toggle="tab" href="#details" role="tab">Details</a>
</li>
</ul>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="tab-content" id="contractTemplateTabContent">
<!-- General Info Tab -->
<div class="tab-pane fade show active" id="general" role="tabpanel">
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-contract"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Contract Template Name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Template Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-align-left"></i></span>
</div>
<input type="text" class="form-control" name="description"
placeholder="Contract Template Description" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Contract Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Select Type -</option>
<?php foreach ($contract_types_array as $type) { ?>
<option><?= $type ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Renewal Frequency</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sync-alt"></i></span>
</div>
<select class="form-control select2" name="renewal_frequency">
<option value="">- Select Frequency -</option>
<?php foreach ($renewal_frequency_array as $renewal_frequency) { ?>
<option><?= $renewal_frequency ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<!-- SLA Tab -->
<div class="tab-pane fade" id="sla" role="tabpanel">
<div class="form-row">
<div class="form-group col-md-6">
<label>Low Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_response_time" placeholder="e.g., 24">
</div>
</div>
<div class="form-group col-md-6">
<label>Low Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_resolution_time" placeholder="e.g., 48">
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>Medium Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_response_time" placeholder="e.g., 12">
</div>
</div>
<div class="form-group col-md-6">
<label>Medium Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_resolution_time" placeholder="e.g., 24">
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>High Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bolt"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_response_time" placeholder="e.g., 1">
</div>
</div>
<div class="form-group col-md-6">
<label>High Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-stopwatch"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_resolution_time" placeholder="e.g., 4">
</div>
</div>
</div>
</div>
<!-- Rates & Support Tab -->
<div class="tab-pane fade" id="rates" role="tabpanel">
<div class="form-group">
<label>Standard Hourly Rate</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div>
<input type="text" class="form-control" name="rate_standard" placeholder="e.g., 100">
</div>
</div>
<div class="form-group">
<label>After Hours Hourly Rate</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-moon"></i></span>
</div>
<input type="text" class="form-control" name="rate_after_hours" placeholder="e.g., 150">
</div>
</div>
<div class="form-group">
<label>Support Hours</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="text" class="form-control" name="support_hours" placeholder="e.g., Mon-Fri 9am-5pm">
</div>
</div>
<div class="form-group">
<label>Net Terms</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-invoice-dollar"></i></span>
</div>
<input type="text" class="form-control" name="net_terms" placeholder="e.g., Net 30">
</div>
</div>
</div>
<!-- Details Tab -->
<div class="tab-pane fade" id="details" role="tabpanel">
<div class="form-group">
<textarea class="form-control tinymce" rows="6" name="details" placeholder="Enter Contract Details"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_contract_template" class="btn btn-primary text-bold">
<i class="fa fa-check mr-2"></i>Create Template
</button>
<button type="button" class="btn btn-light" data-dismiss="modal">
<i class="fa fa-times mr-2"></i>Cancel
</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';
?>

View File

@@ -0,0 +1,265 @@
<?php
require_once '../../../includes/modal_header.php';
$contract_template_id = intval($_GET['id']);
$contract_types_array = ['Fully Managed', 'Partialy Managed', 'Break/Fix'];
$update_frequency_array = ['Manual', 'Annually', '2 Year', '3 Year', '5 Year', '7 Year'];
// Fetch existing template
$sql = mysqli_query($mysqli, "SELECT * FROM contract_templates WHERE contract_template_id = $contract_template_id LIMIT 1");
$row = mysqli_fetch_array($sql);
// Assign locals
$name = nullable_htmlentities($row['contract_template_name']);
$description = nullable_htmlentities($row['contract_template_description']);
$type = nullable_htmlentities($row['contract_template_type']);
$renewal_frequency = nullable_htmlentities($row['contract_template_renewal_frequency']);
$sla_low_resp = intval($row['contract_template_sla_low_response_time']);
$sla_med_resp = intval($row['contract_template_sla_medium_response_time']);
$sla_high_resp = intval($row['contract_template_sla_high_response_time']);
$sla_low_res = intval($row['contract_template_sla_low_resolution_time']);
$sla_med_res = intval($row['contract_template_sla_medium_resolution_time']);
$sla_high_res = intval($row['contract_template_sla_high_resolution_time']);
$hourly_rate = intval($row['contract_template_rate_standard']);
$after_hours = intval($row['contract_template_rate_after_hours']);
$support_hours = nullable_htmlentities($row['contract_template_support_hours']);
$net_terms = intval($row['contract_template_net_terms']);
$details = nullable_htmlentities($row['contract_template_details']);
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-contract mr-2"></i>Edit Contract Template</h5>
<button type="button" class="close text-white" data-dismiss="modal"><span>&times;</span></button>
</div>
<!-- Tabs Navigation -->
<ul class="modal-header nav nav-pills nav-justified">
<li class="nav-item">
<a class="nav-link active" id="general-tab" data-toggle="tab" href="#general" role="tab">General Info</a>
</li>
<li class="nav-item">
<a class="nav-link" id="sla-tab" data-toggle="tab" href="#sla" role="tab">SLA</a>
</li>
<li class="nav-item">
<a class="nav-link" id="rates-tab" data-toggle="tab" href="#rates" role="tab">Rates & Support</a>
</li>
<li class="nav-item">
<a class="nav-link" id="details-tab" data-toggle="tab" href="#details" role="tab">Details</a>
</li>
</ul>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="contract_template_id" value="<?php echo $contract_template_id; ?>">
<div class="modal-body">
<div class="tab-content" id="contractTemplateTabContent">
<!-- General Info Tab -->
<div class="tab-pane fade show active" id="general" role="tabpanel">
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-contract"></i></span>
</div>
<input type="text" class="form-control" name="name"
placeholder="Contract Template Name" maxlength="200" required autofocus
value="<?= $name ?>">
</div>
</div>
<div class="form-group">
<label>Template Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-align-left"></i></span>
</div>
<input type="text" class="form-control" name="description"
placeholder="Contract Template Description" maxlength="200" required
value="<?= $description ?>">
</div>
</div>
<div class="form-group">
<label>Contract Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Select Type -</option>
<?php foreach ($contract_types_array as $type_select) { ?>
<option <?php if ($type == $type_select) { echo "selected"; } ?>><?= $type_select ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Renewal Frequency</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sync-alt"></i></span>
</div>
<select class="form-control select2" name="renewal_frequency">
<option value="">- Select Frequency -</option>
<?php foreach ($renewal_frequency_array as $renewal_frequency_select) { ?>
<option <?php if ($renewal_frequency == $renewal_frequency_select) { echo "selected"; } ?>><?= $renewal_frequency_select ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
<!-- SLA Tab -->
<div class="tab-pane fade" id="sla" role="tabpanel">
<div class="form-row">
<div class="form-group col-md-6">
<label>Low Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_response_time" placeholder="e.g., 24"
value="<?= $sla_low_resp ?>">
</div>
</div>
<div class="form-group col-md-6">
<label>Low Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_low_resolution_time" placeholder="e.g., 48"
value="<?= $sla_low_res ?>">
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>Medium Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_response_time" placeholder="e.g., 12"
value="<?= $sla_med_resp ?>">
</div>
</div>
<div class="form-group col-md-6">
<label>Medium Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-hourglass-half"></i></span>
</div>
<input type="number" class="form-control" name="sla_medium_resolution_time" placeholder="e.g., 24"
value="<?= $sla_med_res ?>">
</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>High Priority Response (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-bolt"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_response_time" placeholder="e.g., 1"
value="<?= $sla_high_resp ?>">
</div>
</div>
<div class="form-group col-md-6">
<label>High Priority Resolution (hrs)</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-stopwatch"></i></span>
</div>
<input type="number" class="form-control" name="sla_high_resolution_time" placeholder="e.g., 4"
value="<?= $sla_high_res ?>">
</div>
</div>
</div>
</div>
<!-- Rates & Support Tab -->
<div class="tab-pane fade" id="rates" role="tabpanel">
<div class="form-group">
<label>Standard Hourly Rate</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-dollar-sign"></i></span>
</div>
<input type="text" class="form-control" name="rate_standard" placeholder="e.g., 100"
value="<?= $rate_standard ?>">
</div>
</div>
<div class="form-group">
<label>After Hours Hourly Rate</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-moon"></i></span>
</div>
<input type="text" class="form-control" name="rate_after_hours" placeholder="e.g., 150"
value="<?= $rate_after_hours ?>">
</div>
</div>
<div class="form-group">
<label>Support Hours</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="text" class="form-control" name="support_hours" placeholder="e.g., Mon-Fri 9am-5pm"
value="<?= $support_hours ?>">
</div>
</div>
<div class="form-group">
<label>Net Terms</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-file-invoice-dollar"></i></span>
</div>
<input type="text" class="form-control" name="net_terms" placeholder="e.g., Net 30"
value="<?= $net_terms ?>">
</div>
</div>
</div>
<!-- Details Tab -->
<div class="tab-pane fade" id="details" role="tabpanel">
<div class="form-group">
<label>Contract Details</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-align-left"></i></span>
</div>
<textarea class="form-control tinymce" rows="6" name="details"
placeholder="Enter Contract Details"><?= $details ?></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="edit_contract_template" class="btn btn-primary text-bold">
<i class="fa fa-check mr-2"></i>Save Changes
</button>
<button type="button" class="btn btn-light" data-dismiss="modal">
<i class="fa fa-times mr-2"></i>Cancel
</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';
?>

View File

@@ -1,83 +1,88 @@
<div class="modal" id="addLinkModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-external-link-alt mr-2"></i>New Custom Link</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<?php
<div class="modal-body">
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-list-ul"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Link name" maxlength="200" required autofocus>
</div>
</div>
ob_start();
<div class="form-group">
<label>Order</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sort-numeric-down"></i></span>
</div>
<input type="number" class="form-control" name="order" placeholder="Leave blank for no order">
</div>
</div>
?>
<div class="form-group">
<label>URI <strong class="text-danger">*</strong></label> / <span class="text-secondary">Open New Tab</span>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-external-link-alt"></i></span>
</div>
<input type="text" class="form-control" name="uri" placeholder="Enter Link" maxlength="500" required>
<div class="input-group-append">
<div class="input-group-text">
<input type="checkbox" name="new_tab" value="1">
</div>
</div>
</div>
</div>
<div class="form-group">
<label>Icon</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-image"></i></span>
</div>
<input type="text" class="form-control" name="icon" placeholder="Icon ex handshake" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Location <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-home"></i></span>
</div>
<select class="form-control select2" name="location" required>
<option value="1">Main Side Nav</option>
<option value="2">Top Nav (Icon Required)</option>
<option value="3">Client Portal Nav</option>
<option value="4">Admin Nav</option>
<option value="5">Reports Nav</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_custom_link" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-external-link-alt mr-2"></i>New Custom Link</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-list-ul"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Link name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Order</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sort-numeric-down"></i></span>
</div>
<input type="number" class="form-control" name="order" placeholder="Leave blank for no order">
</div>
</div>
<div class="form-group">
<label>URI <strong class="text-danger">*</strong></label> / <span class="text-secondary">Open New Tab</span>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-external-link-alt"></i></span>
</div>
<input type="text" class="form-control" name="uri" placeholder="Enter Link" maxlength="500" required>
<div class="input-group-append">
<div class="input-group-text">
<input type="checkbox" name="new_tab" value="1">
</div>
</div>
</div>
</div>
<div class="form-group">
<label>Icon</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-image"></i></span>
</div>
<input type="text" class="form-control" name="icon" placeholder="Icon ex handshake" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Location <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-home"></i></span>
</div>
<select class="form-control select2" name="location" required>
<option value="1">Main Side Nav</option>
<option value="2">Top Nav (Icon Required)</option>
<option value="3">Client Portal Nav</option>
<option value="4">Admin Nav</option>
<option value="5">Reports Nav</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_custom_link" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,49 +1,87 @@
<div class="modal" id="addDocumentTemplateModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-alt mr-2"></i>Creating Document Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<?php
<div class="form-group">
<input type="text" class="form-control" name="name" placeholder="Template name" maxlength="200">
</div>
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Enter a prompt for the type of IT documentation you want to generate:</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="aiPrompt" placeholder="e.g. 'A network troubleshooting guide for junior technicians'">
<div class="input-group-append">
<button class="btn btn-info" type="button" id="generateAIContent">
<i class="fa fa-fw fa-magic mr-1"></i>Generate with AI
</button>
</div>
</div>
</div>
ob_start();
<!-- TinyMCE Content -->
<div class="form-group">
<textarea class="form-control tinymce" name="content"></textarea>
</div>
?>
<div class="form-group">
<input type="text" class="form-control" name="description" placeholder="Enter a short summary">
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_document_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-file-alt mr-2"></i>Creating Document Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<input type="text" class="form-control" name="name" placeholder="Template name" maxlength="200">
</div>
<div class="form-group">
<label>Enter a prompt for the type of IT documentation you want to generate:</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="aiPrompt" placeholder="e.g. 'A network troubleshooting guide for junior technicians'">
<div class="input-group-append">
<button class="btn btn-info" type="button" id="generateAIContent">
<i class="fa fa-fw fa-magic mr-1"></i>Generate with AI
</button>
</div>
</div>
</div>
<!-- TinyMCE Content -->
<div class="form-group">
<textarea class="form-control tinymce" name="content"></textarea>
</div>
<div class="form-group">
<input type="text" class="form-control" name="description" placeholder="Enter a short summary">
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_document_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<script>
$(document).ready(function(){
$('#generateAIContent').on('click', function(){
var prompt = $('#aiPrompt').val().trim();
if(prompt === '') {
alert('Please enter a prompt.');
return;
}
$('#generateAIContent').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Generating...');
$.ajax({
url: '/agent/ajax.php?ai_create_document_template', // The PHP script that calls the OpenAI API
method: 'POST',
data: { prompt: prompt },
dataType: 'html',
success: function(response) {
// Assuming you have exactly one TinyMCE instance on the page
// and it's targeting the .tinymce textarea:
tinymce.activeEditor.setContent(response);
},
error: function() {
alert('Error generating content. Please try again.');
},
complete: function() {
$('#generateAIContent').prop('disabled', false).html('<i class="fa fa-fw fa-magic mr-1"></i>Generate with AI');
}
});
});
});
</script>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,37 +1,42 @@
<div class="modal" id="addPaymentMethodModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i>Creating: <strong>Payment Method</strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<?php
<div class="modal-body">
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-credit-card"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Payment method name" maxlength="200" required autofocus>
</div>
</div>
ob_start();
<div class="form-group">
<textarea class="form-control" rows="3" name="description" placeholder="Enter a description..."></textarea>
</div>
?>
</div>
<div class="modal-footer">
<button type="submit" name="add_payment_method" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i>Creating: <strong>Payment Method</strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-credit-card"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Payment method name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<textarea class="form-control" rows="3" name="description" placeholder="Enter a description..."></textarea>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_payment_method" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -22,7 +22,7 @@ ob_start();
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="payment_method_id" value="<?= $payment_method_id ?>">
<div class="modal-body">
<div class="form-group">

View File

@@ -1,103 +1,203 @@
<div class="form-group">
<div class="modal" id="addPaymentProviderModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment Provider</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
<?php
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment Provider</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="alert alert-info text-center">
<h6>Before Adding a Payment Provider!</h6>
We recommend you add an <strong>Account</strong> and <strong>Vendor</strong> based off the Provider name before continuing eg <strong>Stripe</strong>
</div>
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-expense">Expense</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-details">
<div class="form-group">
<label>Provider <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-credit-card"></i></span>
</div>
<select class="form-control select2" name="provider">
<option>Stripe</option>
</select>
</div>
</div>
<div class="form-group">
<label>Publishable key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<input type="text" class="form-control" name="public_key" placeholder="Publishable API Key (pk_...)">
</div>
</div>
<div class="form-group">
<label>Secret key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="private_key" placeholder="Secret API Key (sk_...)">
</div>
</div>
<div class="form-group">
<label>Income / Expense Account <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-piggy-bank"></i></span>
</div>
<select class="form-control select2" name="account" required>
<option value="">- Select an Account -</option>
<?php
$sql = mysqli_query($mysqli, "SELECT account_id, account_name FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$account_id = intval($row['account_id']);
$account_name = nullable_htmlentities($row['account_name']);
?>
<option <?php if ($account_name === 'Stripe') { echo "selected"; } ?> value="<?= $account_id ?>"><?= $account_name ?></option>
<?php
}
?>
</select>
</div>
</div>
<div class="form-group">
<label>Threshold</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00">
</div>
<small class="form-text text-muted">Will not show as an option at Checkout if invoice amount is above this number, 0 disables the threshold check.</small>
</div>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="tab-pane fade" id="pills-expense">
<div class="alert alert-info">
An income account named after the provider will always be created and used for income of paid invoices.<br>
If "Enable Expense" option is enabled, a matching vendor will also be automatically created for expense tracking. Additionally, an expense category named "Payment Processing" will be created.
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="enable_expense" checked value="1" id="enableExpenseSwitch">
<label class="custom-control-label" for="enableExpenseSwitch">Enable Expense</label>
</div>
<div class="form-group">
<label>Provider <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-credit-card"></i></span>
</div>
<select class="form-control select2" name="provider">
<option>Stripe</option>
</select>
</div>
</div>
<div class="form-group">
<label>Publishable key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<input type="text" class="form-control" name="public_key" placeholder="Publishable API Key (pk_...)">
</div>
</div>
<div class="form-group">
<label>Secret key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="private_key" placeholder="Secret API Key (sk_...)">
</div>
</div>
<div class="form-group">
<label>Threshold</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00">
</div>
<small class="form-text text-muted">Will not show as an option at Checkout if invoice amount is above this number, 0 disables the threshold check.</small>
</div>
<hr>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="enable_expense" checked value="1" id="enableExpenseSwitch">
<label class="custom-control-label" for="enableExpenseSwitch">Enable Expense</label>
</div>
</div>
<div class="form-group">
<label>Percentage Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" placeholder="Enter Percentage">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
<label>Flat Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" placeholder="0.030">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_payment_provider" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Add</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
<div class="form-group">
<label>Payment Provider Vendor <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-building"></i></span>
</div>
<select class="form-control select2" name="expense_vendor" required>
<option value="0">Expense Disabled</option>
<?php
$sql = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE vendor_client_id = 0 AND vendor_archived_at IS NULL ORDER BY vendor_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$vendor_id = intval($row['vendor_id']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
?>
<option <?php if ($vendor_name === 'Stripe') { echo "selected"; } ?> value="<?= $vendor_id ?>"><?= $vendor_name ?></option>
<?php
}
?>
</select>
</div>
</div>
</form>
<div class="form-group">
<label>Expense Category <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
</div>
<select class="form-control select2" name="expense_category" required>
<option value="">- Select a Category -</option>
<?php
$sql = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type = 'Expense' AND category_archived_at IS NULL ORDER BY category_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
<option <?php if ($category_name === 'Processing Fee') { echo "selected"; } ?> value="<?= $category_id ?>"><?= $category_name ?></option>
<?php
}
?>
</select>
<div class="input-group-append">
<button class="btn btn-secondary ajax-modal" type="button"
data-modal-url="../admin/modals/category/category_add.php?category=Expense">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
</div>
<div class="form-group">
<label>Percentage Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" placeholder="Enter Percentage">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
<label>Flat Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" placeholder="0.030">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_payment_provider" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Add</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -10,10 +10,10 @@ $row = mysqli_fetch_array($sql);
$provider_name = nullable_htmlentities($row['payment_provider_name']);
$public_key = nullable_htmlentities($row['payment_provider_public_key']);
$private_key = nullable_htmlentities($row['payment_provider_private_key']);
$account_id = nullable_htmlentities($row['payment_provider_account']);
$account_id = intval($row['payment_provider_account']);
$threshold = floatval($row['payment_provider_threshold']);
$vendor_id = nullable_htmlentities($row['payment_provider_expense_vendor']);
$category_id = nullable_htmlentities($row['payment_provider_expense_category']);
$vendor_id = intval($row['payment_provider_expense_vendor']);
$category_id = intval($row['payment_provider_expense_category']);
$percent_fee = floatval($row['payment_provider_expense_percentage_fee']) * 100;
$flat_fee = floatval($row['payment_provider_expense_flat_fee']);
@@ -21,80 +21,170 @@ $flat_fee = floatval($row['payment_provider_expense_flat_fee']);
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i>Editing: <strong><?php echo $provider_name; ?></strong></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-credit-card mr-2"></i>Editing: <strong><?= $provider_name ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="provider_id" value="<?php echo $provider_id; ?>">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<input type="hidden" name="provider_id" value="<?= $provider_id ?>">
<div class="modal-body">
<div class="form-group">
<label>Publishable key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<input type="text" class="form-control" name="public_key" placeholder="Publishable API Key (pk_...)" value="<?php echo $public_key; ?>">
</div>
</div>
<div class="form-group">
<label>Secret key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="private_key" placeholder="Secret API Key (sk_...)" value="<?php echo $private_key; ?>">
</div>
</div>
<div class="form-group">
<label>Threshold</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00" value="<?php echo $threshold; ?>">
</div>
<small class="form-text text-muted">Will not show as an option at Checkout if above this number</small>
</div>
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-expense">Expense</a>
</li>
</ul>
<hr>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="enable_expense" <?php if ($vendor_id) { echo "checked"; } ?> value="1" id="enableEditExpenseSwitch">
<label class="custom-control-label" for="enableEditExpenseSwitch">Enable Expense</label>
</div>
<small>(Category: Payment Processing -- Vendor: <?php echo $provider_name; ?></small>
</div>
<div class="tab-content">
<div class="form-group">
<label>Percentage Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
<div class="tab-pane fade show active" id="pills-details">
<div class="form-group">
<label>Publishable key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<input type="text" class="form-control" name="public_key" placeholder="Publishable API Key (pk_...)" value="<?= $public_key ?>">
</div>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" value="<?php echo $percent_fee; ?>" placeholder="Enter Percentage">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
<label>Flat Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
<div class="form-group">
<label>Secret key <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="private_key" placeholder="Secret API Key (sk_...)" value="<?= $private_key ?>">
</div>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" value="<?php echo $flat_fee; ?>" placeholder="0.030">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
<label>Income / Expense Account <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-piggy-bank"></i></span>
</div>
<select class="form-control select2" name="account" required>
<option value="">- Select an Account -</option>
<?php
$sql = mysqli_query($mysqli, "SELECT account_id, account_name FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$account_id_select = intval($row['account_id']);
$account_name = nullable_htmlentities($row['account_name']);
?>
<option <?php if ($account_id === $account_id_select) { echo "selected"; } ?> value="<?= $account_id_select ?>"><?= $account_name ?></option>
<?php
}
?>
</select>
</div>
</div>
<div class="form-group">
<label>Threshold</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00" value="<?php echo $threshold; ?>">
</div>
<small class="form-text text-muted">Will not show as an option at Checkout if above this number</small>
</div>
</div>
<div class="tab-pane fade" id="pills-expense">
<div class="form-group">
<label>Payment Provider Vendor <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-building"></i></span>
</div>
<select class="form-control select2" name="expense_vendor" required>
<option value="0">Expense Disabled</option>
<?php
$sql = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE vendor_client_id = 0 AND vendor_archived_at IS NULL ORDER BY vendor_name ASC");
while ($row = mysqli_fetch_array($sql)) {
$vendor_id_select = intval($row['vendor_id']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
?>
<option <?php if ($vendor_id === $vendor_id_select) { echo "selected"; } ?>
value="<?= $vendor_id_select ?>"><?= $vendor_name ?>
</option>
<?php
}
?>
</select>
</div>
</div>
<div class="form-group">
<label>Expense Category <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
</div>
<select class="form-control select2" name="expense_category" required>
<option value="">- Select a Category -</option>
<?php
$sql_category = mysqli_query($mysqli, "SELECT category_id, category_name FROM categories WHERE category_type = 'Expense' AND category_archived_at IS NULL ORDER BY category_name ASC");
while ($row = mysqli_fetch_array($sql_category)) {
$category_id_select = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
<option <?php if ($category_id === $category_id_select) { echo "selected"; } ?> value="<?= $category_id_select ?>"><?= $category_name ?></option>
<?php
}
?>
</select>
<div class="input-group-append">
<button class="btn btn-secondary ajax-modal" type="button"
data-modal-url="../admin/modals/category/category_add.php?category=Expense">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
</div>
<div class="form-group">
<label>Percentage Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" value="<?php echo $percent_fee; ?>" placeholder="Enter Percentage">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
<label>Flat Fee to expense</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" value="<?php echo $flat_fee; ?>" placeholder="0.030">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="edit_payment_provider" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button>

View File

@@ -1,41 +1,45 @@
<div class="modal" id="addProjectTemplateModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-project-diagram mr-2"></i>Creating Project Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<?php
<div class="modal-body">
<div class="form-group">
<label>Project Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Project Template Name" maxlength="255" required autofocus>
</div>
</div>
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Description">
</div>
</div>
ob_start();
</div>
<div class="modal-footer">
<button type="submit" name="add_project_template" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-project-diagram mr-2"></i>Creating Project Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<label>Project Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Project Template Name" maxlength="255" required autofocus>
</div>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Description">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_project_template" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,44 +1,56 @@
<div class="modal" id="editProjectTemplateModal<?php echo $project_template_id; ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-project-diagram mr-2"></i>Editing Project Template: <strong><?php echo $project_template_name; ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="project_template_id" value="<?php echo $project_template_id; ?>">
<?php
<div class="modal-body">
<div class="form-group">
<label>Project Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Project Template Name" maxlength="255" value="<?php echo $project_template_name; ?>" required autofocus>
</div>
</div>
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Description" value="<?php echo $project_template_description; ?>">
</div>
</div>
$project_template_id = intval($_GET['project_template_id']);
</div>
<div class="modal-footer">
<button type="submit" name="edit_project_template" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
$sql = mysqli_query($mysqli, "SELECT * FROM project_templates WHERE project_template_id = $project_template_id LIMIT 1");
$row = mysqli_fetch_array($sql);
$project_template_name = nullable_htmlentities($row['project_template_name']);
$project_template_description = nullable_htmlentities($row['project_template_description']);
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-project-diagram mr-2"></i>Editing Project Template: <strong><?php echo $project_template_name; ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="project_template_id" value="<?php echo $project_template_id; ?>">
<div class="modal-body">
<div class="form-group">
<label>Project Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Project Template Name" maxlength="255" value="<?php echo $project_template_name; ?>" required autofocus>
</div>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Description" value="<?php echo $project_template_description; ?>">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="edit_project_template" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,64 +1,71 @@
<div class="modal" id="addProjectTemplateTicketTemplateModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-life-ring mr-2"></i>Adding Ticket Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="project_template_id" value="<?php echo $project_template_id; ?>">
<div class="modal-body">
<?php
<div class="form-group">
<label>Ticket Template <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-life-ring"></i></span>
</div>
<select class="form-control select2" name="ticket_template_id" required>
<option value="">- Select a Ticket Template -</option>
<?php
require_once '../../../includes/modal_header.php';
$sql_ticket_templates_select = mysqli_query($mysqli, "SELECT ticket_template_id, ticket_template_name FROM ticket_templates
WHERE ticket_template_id NOT IN (
SELECT ticket_template_id FROM project_template_ticket_templates
WHERE project_template_id = $project_template_id
)
AND ticket_template_archived_at IS NULL
ORDER BY ticket_template_name ASC"
);
while ($row = mysqli_fetch_array($sql_ticket_templates_select)) {
$ticket_template_id_select = intval($row['ticket_template_id']);
$ticket_template_name_select = nullable_htmlentities($row['ticket_template_name']);
?>
<option value="<?php echo $ticket_template_id_select; ?>"><?php echo $ticket_template_name_select; ?></option>
<?php
}
$project_template_id = intval($_GET['project_template_id']);
?>
</select>
</div>
</div>
ob_start();
<div class="form-group">
<label>Order</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sort-numeric-down"></i></span>
</div>
<input type="text" class="form-control" name="order" value="1">
</div>
</div>
?>
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_template_to_project_template" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Add</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-life-ring mr-2"></i>Adding Ticket Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="project_template_id" value="<?php echo $project_template_id; ?>">
<div class="modal-body">
<div class="form-group">
<label>Ticket Template <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-life-ring"></i></span>
</div>
<select class="form-control select2" name="ticket_template_id" required>
<option value="">- Select a Ticket Template -</option>
<?php
$sql_ticket_templates_select = mysqli_query($mysqli, "SELECT ticket_template_id, ticket_template_name FROM ticket_templates
WHERE ticket_template_id NOT IN (
SELECT ticket_template_id FROM project_template_ticket_templates
WHERE project_template_id = $project_template_id
)
AND ticket_template_archived_at IS NULL
ORDER BY ticket_template_name ASC"
);
while ($row = mysqli_fetch_array($sql_ticket_templates_select)) {
$ticket_template_id_select = intval($row['ticket_template_id']);
$ticket_template_name_select = nullable_htmlentities($row['ticket_template_name']);
?>
<option value="<?php echo $ticket_template_id_select; ?>"><?php echo $ticket_template_name_select; ?></option>
<?php
}
?>
</select>
</div>
</div>
<div class="form-group">
<label>Order</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-sort-numeric-down"></i></span>
</div>
<input type="text" class="form-control" name="order" value="1">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_template_to_project_template" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Add</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,58 +1,62 @@
<div class="modal" id="addRoleModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-user-shield mr-2"></i>Add new role</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="tab-content">
<?php
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<input type="text" class="form-control" name="role_name" placeholder="Role Name" maxlength="200" required>
</div>
</div>
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-chevron-right"></i></span>
</div>
<input type="text" class="form-control" name="role_description" placeholder="Role Description" maxlength="200" required>
</div>
</div>
ob_start();
<div class="form-group">
<label>Admin Access <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tools"></i></span>
</div>
<select class="form-control select2" name="role_is_admin" required>
<option value="0">No - edit after creation to set permissions</option>
<option value="1">Yes - this role should have full admin access</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_role" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-user-shield mr-2"></i>New Role</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="tab-content">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<input type="text" class="form-control" name="role_name" placeholder="Role Name" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Description <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-chevron-right"></i></span>
</div>
<input type="text" class="form-control" name="role_description" placeholder="Role Description" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Admin Access <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tools"></i></span>
</div>
<select class="form-control select2" name="role_is_admin" required>
<option value="0">No - edit after creation to set permissions</option>
<option value="1">Yes - this role should have full admin access</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_role" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,83 +1,88 @@
<div class="modal" id="addSoftwareTemplateModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-cube mr-2"></i>New License Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<?php
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Software name" maxlength="200" required autofocus>
</div>
</div>
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Version</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<input type="text" class="form-control" name="version" placeholder="Software version" maxlength="200">
</div>
</div>
ob_start();
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Short description">
</div>
</div>
?>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Type -</option>
<?php foreach($software_types_array as $software_type) { ?>
<option><?php echo $software_type; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>License Type</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<select class="form-control select2" name="license_type">
<option value="">- Select a License Type -</option>
<?php foreach($license_types_array as $license_type) { ?>
<option><?php echo $license_type; ?></option>
<?php } ?>
</select>
</div>
</div>
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"></textarea>
</div>
<div class="modal-footer">
<button type="submit" name="add_software_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-cube mr-2"></i>New License Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Software name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Version</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<input type="text" class="form-control" name="version" placeholder="Software version" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Short description">
</div>
</div>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Type -</option>
<?php foreach($software_types_array as $software_type) { ?>
<option><?php echo $software_type; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>License Type</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<select class="form-control select2" name="license_type">
<option value="">- Select a License Type -</option>
<?php foreach($license_types_array as $license_type) { ?>
<option><?php echo $license_type; ?></option>
<?php } ?>
</select>
</div>
</div>
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"></textarea>
</div>
<div class="modal-footer">
<button type="submit" name="add_software_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -15,8 +15,11 @@ if (isset($_GET['type'])) {
$type_display = "Contact";
} elseif ($type === 4) {
$type_display = "Credential";
} elseif ($type === 5) {
$type_display = "Asset";
}
}
ob_start();
?>
@@ -57,6 +60,7 @@ if (isset($_GET['type'])) {
<option value="2">Location Tag</option>
<option value="3">Contact Tag</option>
<option value="4">Credential Tag</option>
<option value="5">Asset Tag</option>
</select>
</div>
</div>
@@ -85,7 +89,7 @@ if (isset($_GET['type'])) {
</div>
<div class="modal-footer">
<button type="submit" name="add_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="submit" name="add_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create Tag</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>

View File

@@ -12,11 +12,24 @@ $tag_type = intval($row['tag_type']);
$tag_color = nullable_htmlentities($row['tag_color']);
$tag_icon = nullable_htmlentities($row['tag_icon']);
// Generate the HTML form content using output buffering.
if ($tag_type == 1) {
$tag_type_display = "Client";
} elseif ( $tag_type == 2) {
$tag_type_display = "Location";
} elseif ( $tag_type == 3) {
$tag_type_display = "Contact";
} elseif ( $tag_type == 4) {
$tag_type_display = "Credential";
} elseif ( $tag_type == 5) {
$tag_type_display = "Asset";
} else {
$tag_type_display = "Unknown";
}
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-tag mr-2"></i>Editing tag: <strong><?php echo $tag_name; ?></strong></h5>
<h5 class="modal-title"><i class="fas fa-fw fa-tag mr-2"></i><?= $tag_type_display ?> Tag: <strong><?php echo $tag_name; ?></strong></h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
@@ -35,22 +48,6 @@ ob_start();
</div>
</div>
<div class="form-group">
<label>Type <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-th"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Type -</option>
<option value="1" <?php if ($tag_type == 1) { echo "selected"; } ?>>Client Tag</option>
<option value="2" <?php if ($tag_type == 2) { echo "selected"; } ?>>Location Tag</option>
<option value="3" <?php if ($tag_type == 3) { echo "selected"; } ?>>Contact Tag</option>
<option value="4" <?php if ($tag_type == 4) { echo "selected"; } ?>>Credential Tag</option>
</select>
</div>
</div>
<div class="form-group">
<label>Color <strong class="text-danger">*</strong></label>
<div class="input-group">
@@ -73,7 +70,7 @@ ob_start();
</div>
<div class="modal-footer">
<button type="submit" name="edit_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
<button type="submit" name="edit_tag" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save changes</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>

View File

@@ -1,30 +1,35 @@
<div class="modal" id="addTaxModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-balance-scale mr-2"></i>New Tax</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<?php
<div class="modal-body">
<div class="form-group">
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-balance-scale mr-2"></i>New Tax</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<input type="text" class="form-control" name="name" placeholder="Tax name" maxlength="200" required autofocus>
</div>
<div class="form-group">
</div>
<div class="form-group">
<label>Percent <strong class="text-danger">*</strong></label>
<input type="number" min="0" step="any" class="form-control col-md-4" name="percent">
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_tax" class="btn btn-primary text-bold"><i class="fa fa-check mr- 2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_tax" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,42 +1,43 @@
<div class="modal" id="addTicketStatusModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-info-circle mr-2"></i>New Ticket Status</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<?php
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-body">
<div class="form-group">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-info-circle mr-2"></i>New Ticket Status</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-info-circle"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Ticket Status name" maxlength="200" required autofocus>
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-info-circle"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Ticket Status name" maxlength="200" required autofocus>
</div>
</div>
</div>
<div class="form-group">
<div class="form-group">
<label>Color <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-paint-brush"></i></span>
</div>
<input type="color" class="form-control col-3" name="color" required>
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-paint-brush"></i></span>
</div>
<input type="color" class="form-control col-3" name="color" required>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_status" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_status" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,75 +1,79 @@
<div class="modal" id="addTicketTemplateModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>Creating Ticket Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
<?php
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>New Ticket Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-life-ring"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Template name" maxlength="200" required autofocus>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
</div>
<div class="form-group">
<label>Template Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-life-ring"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Template name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Subject</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="subject" placeholder="Subject" maxlength="500">
</div>
</div>
<div class="form-group">
<textarea class="form-control tinymceTicket" name="details"></textarea>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Short description">
</div>
</div>
<div class="form-group">
<label>Add it to a Project Template?</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<select class="form-control select2" name="project_template">
<option value="0">- No -</option>
<?php
$sql_project_templates = mysqli_query($mysqli, "SELECT * FROM project_templates WHERE project_template_archived_at IS NULL ORDER BY project_template_name ASC");
while ($row = mysqli_fetch_array($sql_project_templates)) {
$project_template_id_select = intval($row['project_template_id']);
$project_template_name_select = nullable_htmlentities($row['project_template_name']); ?>
<option value="<?php echo $project_template_id_select; ?>"><?php echo $project_template_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Subject</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
<input type="text" class="form-control" name="subject" placeholder="Subject" maxlength="500">
</div>
</div>
<div class="form-group">
<textarea class="form-control tinymceTicket" name="details"></textarea>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
</form>
<input type="text" class="form-control" name="description" placeholder="Short description">
</div>
</div>
<div class="form-group">
<label>Add it to a Project Template?</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-project-diagram"></i></span>
</div>
<select class="form-control select2" name="project_template">
<option value="0">- No -</option>
<?php
$sql_project_templates = mysqli_query($mysqli, "SELECT * FROM project_templates WHERE project_template_archived_at IS NULL ORDER BY project_template_name ASC");
while ($row = mysqli_fetch_array($sql_project_templates)) {
$project_template_id_select = intval($row['project_template_id']);
$project_template_name_select = nullable_htmlentities($row['project_template_name']); ?>
<option value="<?php echo $project_template_id_select; ?>"><?php echo $project_template_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_ticket_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Template</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,156 +1,176 @@
<div class="modal" id="addUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus mr-2"></i>New User</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<?php
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-user-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-user-access">Restrict Access</a>
</li>
</ul>
require_once '../../../includes/modal_header.php';
<hr>
ob_start();
<div class="tab-content">
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus mr-2"></i>New User</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="tab-pane fade show active" id="pills-user-details">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-user-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-user-access">Restrict Access</a>
</li>
</ul>
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Full Name" maxlength="200" required autofocus>
</div>
</div>
<hr>
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200" required>
</div>
</div>
<div class="tab-content">
<div class="form-group">
<label>Password <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="password" class="form-control" data-toggle="password" name="password" id="password" placeholder="Enter a Password" autocomplete="new-password" minlength="8" required>
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<div class="input-group-append">
<span class="btn btn-default"><i class="fa fa-fw fa-question" onclick="generatePassword()"></i></span>
</div>
</div>
</div>
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<option value="">- Role -</option>
<?php
$sql_user_roles = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE role_archived_at IS NULL");
while ($row = mysqli_fetch_array($sql_user_roles)) {
$role_id = intval($row['role_id']);
$role_name = nullable_htmlentities($row['role_name']);
?>
<option value="<?php echo $role_id; ?>"><?php echo $role_name; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Avatar</label>
<input type="file" class="form-control-file" accept="image/*" name="file">
</div>
<div class="form-group" <?php if(empty($config_smtp_host)) { echo "hidden"; } ?>>
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="sendEmailCheckBox" name="send_email" value="" checked>
<label for="sendEmailCheckBox" class="custom-control-label">
Send user e-mail with login details?
</label>
</div>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="forceMFACheckBox" name="force_mfa" value=1>
<label for="forceMFACheckBox" class="custom-control-label">
Force MFA
</label>
</div>
</div>
<div class="tab-pane fade show active" id="pills-user-details">
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Full Name" maxlength="200" required autofocus>
</div>
</div>
<div class="tab-pane fade" id="pills-user-access">
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200" required>
</div>
</div>
<div class="alert alert-info">
Check boxes to authorize user client access. No boxes grant full client access. Admin users are unaffected.
</div>
<div class="form-group">
<label>Password <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="password" class="form-control" data-toggle="password" name="password" id="password" placeholder="Enter a Password" autocomplete="new-password" minlength="8" required>
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<div class="input-group-append">
<span class="btn btn-default"><i class="fa fa-fw fa-question" onclick="generatePassword()"></i></span>
</div>
</div>
</div>
<ul class="list-group">
<li class="list-group-item bg-dark">
<div class="form-check">
<input type="checkbox" class="form-check-input" onclick="this.closest('.tab-pane').querySelectorAll('.client-checkbox').forEach(checkbox => checkbox.checked = this.checked);">
<label class="form-check-label ml-3"><strong>Restrict Access to Clients</strong></label>
</div>
</li>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<option value="">- Role -</option>
<?php
$sql_user_roles = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE role_archived_at IS NULL");
while ($row = mysqli_fetch_array($sql_user_roles)) {
$role_id = intval($row['role_id']);
$role_name = nullable_htmlentities($row['role_name']);
?>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input client-checkbox" name="clients[]" value="<?php echo $client_id; ?>">
<label class="form-check-label ml-3"><?php echo $client_name; ?></label>
</div>
</li>
<?php } ?>
</ul>
</div>
<option value="<?php echo $role_id; ?>"><?php echo $role_name; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
<label>Avatar</label>
<input type="file" class="form-control-file" accept="image/*" name="file">
</div>
<div class="modal-footer">
<button type="submit" name="add_user" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
<div class="form-group" <?php if(empty($config_smtp_host)) { echo "hidden"; } ?>>
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="sendEmailCheckBox" name="send_email" value="" checked>
<label for="sendEmailCheckBox" class="custom-control-label">
Send user e-mail with login details?
</label>
</div>
</div>
</form>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" id="forceMFACheckBox" name="force_mfa" value=1>
<label for="forceMFACheckBox" class="custom-control-label">
Force MFA
</label>
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-user-access">
<div class="alert alert-info">
Check boxes to authorize user client access. No boxes grant full client access. Admin users are unaffected.
</div>
<ul class="list-group">
<li class="list-group-item bg-dark">
<div class="form-check">
<input type="checkbox" class="form-check-input" onclick="this.closest('.tab-pane').querySelectorAll('.client-checkbox').forEach(checkbox => checkbox.checked = this.checked);">
<label class="form-check-label ml-3"><strong>Restrict Access to Clients</strong></label>
</div>
</li>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input client-checkbox" name="clients[]" value="<?php echo $client_id; ?>">
<label class="form-check-label ml-3"><?php echo $client_name; ?></label>
</div>
</li>
<?php } ?>
</ul>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_user" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<script>
function generatePassword() {
jQuery.get(
"/agent/ajax.php", {
get_readable_pass: 'true'
},
function(data) {
const password = JSON.parse(data);
document.getElementById("password").value = password;
}
);
}
</script>
<?php
require_once "../../../includes/modal_footer.php";

View File

@@ -1,31 +1,35 @@
<div class="modal" id="resetAllUserPassModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-body">
<div class="mb-4" style="text-align: center;">
<i class="far fas fa-10x fa-skull-crossbones text-danger mb-3 mt-3"></i>
<h2>Incident Response: Agent Password Reset</h2>
<br>
<div class="alert alert-danger" role="alert">
<b>This is a potentially destructive function.<br>It is intended to be used as part of a potential security incident.</b>
</div>
<h6 class="mb-4 text-secondary"><b>All ITFlow agent passwords will be reset and shown to you </b><i>(except yours - change yours first!)</i>.<br/><br/>You should communicate temporary passwords to agents out of band (e.g. via a phone call) and require they are changed ASAP.</h6>
<form action="post.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="row col-7 offset-4">
<div class="input-group">
<div class="input-group-prepend">
<input type="password" class="form-control" placeholder="Enter your account password to continue" name="admin_password" required>
</div>
</div>
</div>
<br>
<button class="btn btn-danger" type="submit" name="ir_reset_user_password"><i class="fas fa-fw fa-key mr-2"></i>Reset passwords</button>
</form>
</div>
<button type="button" class="btn btn-outline-secondary btn-lg px-5 mr-4" data-dismiss="modal">Cancel</button>
<?php
</div>
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-body">
<div class="mb-4" style="text-align: center;">
<i class="far fas fa-10x fa-skull-crossbones text-danger mb-3 mt-3"></i>
<h2>Incident Response: Agent Password Reset</h2>
<br>
<div class="alert alert-danger" role="alert">
<b>This is a potentially destructive function.<br>It is intended to be used as part of a potential security incident.</b>
</div>
<h6 class="mb-4 text-secondary"><b>All ITFlow agent passwords will be reset and shown to you </b><i>(except yours - change yours first!)</i>.<br/><br/>You should communicate temporary passwords to agents out of band (e.g. via a phone call) and require they are changed ASAP.</h6>
<form action="post.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="row col-7 offset-4">
<div class="input-group">
<div class="input-group-prepend">
<input type="password" class="form-control" placeholder="Enter your account password to continue" name="admin_password" required>
</div>
</div>
</div>
<br>
<button class="btn btn-danger" type="submit" name="ir_reset_user_password"><i class="fas fa-fw fa-key mr-2"></i>Reset passwords</button>
</form>
</div>
<button type="button" class="btn btn-outline-secondary btn-lg px-5 mr-4" data-dismiss="modal">Cancel</button>
</div>
<?php
require_once "../../../includes/modal_footer.php";

View File

@@ -94,11 +94,14 @@ ob_start();
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<input type="password" class="form-control" data-toggle="password" name="new_password"
<input type="password" class="form-control" data-toggle="password" name="new_password" id="password"
placeholder="Leave Blank For No Password Change" autocomplete="new-password">
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
<div class="input-group-append">
<span class="btn btn-default"><i class="fa fa-fw fa-question" onclick="generatePassword()"></i></span>
</div>
</div>
</div>
@@ -200,5 +203,23 @@ ob_start();
</div>
</form>
<script>
function generatePassword() {
// Send a GET request to ajax.php as ajax.php?get_readable_pass=true
jQuery.get(
"/agent/ajax.php", {
get_readable_pass: 'true'
},
function(data) {
//If we get a response from post.php, parse it as JSON
const password = JSON.parse(data);
document.getElementById("password").value = password;
}
);
}
</script>
<?php
require_once "../../../includes/modal_footer.php";

View File

@@ -1,21 +1,26 @@
<div class="modal" id="exportUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-download mr-2"></i>Export Users to CSV</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<?php
</div>
<div class="modal-footer">
<button type="submit" name="export_users_csv" class="btn btn-primary text-bold"><i class="fas fa-fw fa-download mr-2"></i>Download CSV</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
require_once '../../../includes/modal_header.php';
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-download mr-2"></i>Export Users to CSV</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="submit" name="export_users_csv" class="btn btn-primary text-bold"><i class="fas fa-fw fa-download mr-2"></i>Download CSV</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -1,45 +1,49 @@
<div class="modal" id="userInviteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus"></i>Invite User</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<?php
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200" required>
</div>
</div>
require_once '../../../includes/modal_header.php';
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<option value="">- Role -</option>
<!-- //TODO: Pull from roles -->
</select>
</div>
</div>
ob_start();
</div>
<div class="modal-footer">
<button type="submit" name="invite_user" class="btn btn-primary text-bold"><i class="fas fa-paper-plane mr-2"></i>Send Invite</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus"></i>Invite User</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="modal-body">
<div class="form-group">
<label>Email <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Email Address" maxlength="200" required>
</div>
</div>
<div class="form-group">
<label>Role <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div>
<select class="form-control select2" name="role" required>
<option value="">- Role -</option>
<!-- //TODO: Pull from roles -->
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="invite_user" class="btn btn-primary text-bold"><i class="fas fa-paper-plane mr-2"></i>Send Invite</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once "../../../includes/modal_footer.php";

View File

@@ -1,168 +1,171 @@
<div class="modal" id="addVendorTemplateModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-building mr-2"></i>New Vendor Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<?php
<input type="hidden" name="client_id" value="<?php if (isset($_GET['client_id'])) { echo $client_id; } else { echo 0; } ?>">
require_once '../../../includes/modal_header.php';
<div class="modal-body">
ob_start();
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-support">Support</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-notes">Notes</a>
</li>
</ul>
?>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-details">
<div class="form-group">
<label>Vendor Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-building"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Vendor Name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Description" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Account Number</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-fingerprint"></i></span>
</div>
<input type="text" class="form-control" name="account_number" placeholder="Account number" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Account Manager</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="contact_name" placeholder="Account manager's name" maxlength="200">
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-support">
<label>Support Phone / <span class="text-secondary">Extension</span></label>
<div class="form-row">
<div class="col-9">
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
</div>
<input type="tel" class="form-control col-2" name="phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200">
</div>
</div>
</div>
<div class="col-3">
<div class="form-group">
<input type="text" class="form-control" name="extension" placeholder="ext." maxlength="200">
</div>
</div>
</div>
<div class="form-group">
<label>Support Hours</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="text" class="form-control" name="hours" placeholder="Support Hours" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Support Email</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Support Email" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Support Website URL</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-globe"></i></span>
</div>
<input type="text" class="form-control" name="website" placeholder="Do not include http(s)://" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Pin/Code</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="code" placeholder="Access Code or Pin" maxlength="200">
</div>
</div>
<div class="form-group">
<label>SLA</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-handshake"></i></span>
</div>
<input type="text" class="form-control" name="sla" placeholder="SLA Response Time" maxlength="200">
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-notes">
<div class="form-group">
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_vendor_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Template</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
</div>
</div>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fas fa-fw fa-building mr-2"></i>New Vendor Template</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<div class="modal-body">
<ul class="nav nav-pills nav-justified mb-3">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#pills-details">Details</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-support">Support</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#pills-notes">Notes</a>
</li>
</ul>
<hr>
<div class="tab-content">
<div class="tab-pane fade show active" id="pills-details">
<div class="form-group">
<label>Vendor Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-building"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Vendor Name" maxlength="200" required autofocus>
</div>
</div>
<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-angle-right"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Description" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Account Number</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-fingerprint"></i></span>
</div>
<input type="text" class="form-control" name="account_number" placeholder="Account number" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Account Manager</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="contact_name" placeholder="Account manager's name" maxlength="200">
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-support">
<label>Support Phone / <span class="text-secondary">Extension</span></label>
<div class="form-row">
<div class="col-9">
<div class="form-group">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
</div>
<input type="tel" class="form-control col-2" name="phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200">
</div>
</div>
</div>
<div class="col-3">
<div class="form-group">
<input type="text" class="form-control" name="extension" placeholder="ext." maxlength="200">
</div>
</div>
</div>
<div class="form-group">
<label>Support Hours</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
</div>
<input type="text" class="form-control" name="hours" placeholder="Support Hours" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Support Email</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
</div>
<input type="email" class="form-control" name="email" placeholder="Support Email" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Support Website URL</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-globe"></i></span>
</div>
<input type="text" class="form-control" name="website" placeholder="Do not include http(s)://" maxlength="200">
</div>
</div>
<div class="form-group">
<label>Pin/Code</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="text" class="form-control" name="code" placeholder="Access Code or Pin" maxlength="200">
</div>
</div>
<div class="form-group">
<label>SLA</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-handshake"></i></span>
</div>
<input type="text" class="form-control" name="sla" placeholder="SLA Response Time" maxlength="200">
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-notes">
<div class="form-group">
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="add_vendor_template" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Template</button>
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
</div>
</form>
<?php
require_once '../../../includes/modal_footer.php';

113
admin/modules.php Normal file
View File

@@ -0,0 +1,113 @@
<?php
// Default Column Sortby Filter
$sort = "module_name";
$order = "DESC";
require_once "includes/inc_all_admin.php";
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM modules
WHERE (module_name LIKE '%$q%' OR module_description LIKE '%$q%')
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-puzzle-piece mr-2"></i>Access Modules</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/module/module_add.php">
<i class="fas fa-fw fa-plus mr-2"></i>New Module
</button>
</div>
</div>
</div>
<div class="card-body">
<form class="mb-4" autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) {echo stripslashes(nullable_htmlentities($q));} ?>" placeholder="Search Modules">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?> text-nowrap">
<tr>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=module_name&order=<?php echo $disp; ?>">
Module <?php if ($sort == 'module_name') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$module_id = intval($row['module_id']);
$module_name = nullable_htmlentities($row['module_name']);
$module_description = nullable_htmlentities($row['module_description']);
?>
<tr>
<td>
<a href="#" <?php if ($module_id > 6) { ?> class="ajax-modal" data-modal-url="modals/modules/module_edit.php?id=<?= $module_id ?>" <?php } ?>>
<strong class="text-dark"><?= $module_name ?></strong>
</a>
<div class="text-secondary"><?= $module_description ?></div>
</td>
<td>
<?php if ($module_id > 6) { ?>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/module/module_edit.php?id=<?= $module_id ?>">
<i class="fas fa-fw fa-user-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_module=<?= $module_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Delete
</a>
</div>
</div>
<?php } else { echo "<p class='text-center'>N/A Predefined</p>"; } ?>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php";
?>
</div>
</div>
<?php
require_once "../includes/footer.php";

View File

@@ -16,7 +16,7 @@ $num_rows = mysqli_num_rows($sql);
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-credit-card mr-2"></i>Payment Methods</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addPaymentMethodModal"><i class="fas fa-plus mr-2"></i>Add Payment Method</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/payment_method/payment_method_add.php"><i class="fas fa-plus mr-2"></i>Add Payment Method</button>
</div>
</div>
<div class="card-body">
@@ -98,5 +98,4 @@ $num_rows = mysqli_num_rows($sql);
</div>
<?php
require_once "modals/payment_method/payment_method_add.php";
require_once "../includes/footer.php";

View File

@@ -6,10 +6,10 @@ $order = "ASC";
require_once "includes/inc_all_admin.php";
$sql = mysqli_query($mysqli, "SELECT * FROM payment_providers
$sql = mysqli_query($mysqli, "SELECT * FROM payment_providers
LEFT JOIN accounts ON payment_provider_account = account_id
LEFT JOIN vendors ON payment_provider_expense_vendor = vendor_id
LEFT JOIN categories ON payment_provider_expense_category = category_id
LEFT JOIN categories ON payment_provider_expense_category = category_id
ORDER BY $sort $order"
);
@@ -21,7 +21,7 @@ $num_rows = mysqli_num_rows($sql);
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-credit-card mr-2"></i>Payment Providers</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addPaymentProviderModal"><i class="fas fa-plus mr-2"></i>Add Provider</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/payment_provider/payment_provider_add.php"><i class="fas fa-plus mr-2"></i>Add Provider</button>
</div>
</div>
<div class="card-body">
@@ -57,7 +57,7 @@ $num_rows = mysqli_num_rows($sql);
<th>
<a class="text-dark">Expensed Fee</a>
</th>
<th>
<th class="text-center">
<a class="text-dark">Saved Payment Methods</a>
</th>
<th class="text-center">Action</th>
@@ -72,7 +72,7 @@ $num_rows = mysqli_num_rows($sql);
$provider_description = nullable_htmlentities($row['payment_provider_description']);
$account_name = nullable_htmlentities($row['account_name']);
$threshold = floatval($row['payment_provider_threshold']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
$vendor_name = nullable_htmlentities($row['vendor_name'] ?? "Expense Disabled");
$category = nullable_htmlentities($row['category_name']);
$percent_fee = floatval($row['payment_provider_expense_percentage_fee']) * 100;
$flat_fee = floatval($row['payment_provider_expense_flat_fee']);
@@ -94,7 +94,9 @@ $num_rows = mysqli_num_rows($sql);
<td><?php echo $vendor_name; ?></td>
<td><?php echo $category; ?></td>
<td><?php echo $percent_fee; ?>% + <?php echo numfmt_format_currency($currency_format, $flat_fee, $session_company_currency); ?></td>
<td><?php echo $saved_payment_count; ?></td>
<td class="text-center">
<a class="badge badge-dark badge-pill p-2" href="saved_payment_method.php"><?= $saved_payment_count ?></a>
</td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
@@ -106,12 +108,14 @@ $num_rows = mysqli_num_rows($sql);
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<!-- <a class="dropdown-item text-danger confirm-link" href="post.php?disable_payment_provider=--><?php //echo $provider_id; ?><!--&csrf_token=--><?php //echo $_SESSION['csrf_token'] ?><!--">-->
<!-- <i class="fas fa-fw fa-thumbs-down mr-2"></i>Disable-->
<!-- </a>-->
<!-- <a class="dropdown-item text-danger confirm-link" href="post.php?delete_payment_provider=--><?php //echo $provider_id; ?><!--&csrf_token=--><?php //echo $_SESSION['csrf_token'] ?><!--">-->
<!-- <i class="fas fa-fw fa-trash mr-2"></i>Delete-->
<!-- </a>-->
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_payment_provider=<?= $provider_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-trash mr-2"></i><strong>Delete Provider and</strong>
<ul class="text-xs">
<li>Related Recurring Payments</li>
<li>Related Saved cards</li>
<li>Client Provider Relations</li>
</ul>
</a>
</div>
</div>
</td>
@@ -135,5 +139,4 @@ $num_rows = mysqli_num_rows($sql);
</div>
<?php
require_once "modals/payment_provider/payment_provider_add.php";
require_once "../includes/footer.php";

View File

@@ -36,7 +36,4 @@ if (isset($session_is_admin) && $session_is_admin) {
require_once "../post/logout.php";
// TODO: Find a home for these
require_once "../post/ai.php";
require_once "../post/misc.php";

View File

@@ -49,7 +49,7 @@ if (isset($_POST['edit_ai_model'])) {
if (isset($_GET['delete_ai_model'])) {
validateCSRFToken($_GET['csrf_token']);
$model_id = intval($_GET['delete_ai_model']);
$model_name = sanitizeInput(getFieldById('ai_models', $model_id, 'ai_model_name'));

View File

@@ -2,185 +2,304 @@
/*
* ITFlow - GET/POST request handler for DB / master key backup
* Rewritten with streaming SQL dump, component checksums, safer zipping, and better headers.
*/
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
require_once "../includes/app_version.php";
if (isset($_GET['download_backup'])) {
validateCSRFToken($_GET['csrf_token']);
$timestamp = date('YmdHis');
$baseName = "itflow_$timestamp";
// --- Optional performance levers for big backups ---
@set_time_limit(0);
if (function_exists('ini_set')) {
@ini_set('memory_limit', '1024M');
}
// === 0. Scoped cleanup ===
$cleanupFiles = [];
/**
* Write a line to a file handle with newline.
*/
function fwrite_ln($fh, string $s): void {
fwrite($fh, $s);
fwrite($fh, PHP_EOL);
}
$registerTempFileForCleanup = function ($file) use (&$cleanupFiles) {
$cleanupFiles[] = $file;
};
register_shutdown_function(function () use (&$cleanupFiles) {
foreach ($cleanupFiles as $file) {
if (is_file($file)) {
@unlink($file);
}
}
});
// === 1. Local helper function: zipFolder
$zipFolder = function ($folderPath, $zipFilePath) {
$zip = new ZipArchive();
if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
error_log("Failed to open zip file: $zipFilePath");
http_response_code(500);
exit("Internal Server Error: Cannot open zip archive.");
}
$folderPath = realpath($folderPath);
if (!$folderPath) {
error_log("Invalid folder path: $folderPath");
http_response_code(500);
exit("Internal Server Error: Invalid folder path.");
}
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($folderPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($folderPath) + 1);
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
};
// === 2. Create all temp files
$sqlFile = tempnam(sys_get_temp_dir(), $baseName . "_sql_");
$uploadsZip = tempnam(sys_get_temp_dir(), $baseName . "_uploads_");
$versionFile = tempnam(sys_get_temp_dir(), $baseName . "_version_");
$finalZip = tempnam(sys_get_temp_dir(), $baseName . "_backup_");
foreach ([$sqlFile, $uploadsZip, $versionFile, $finalZip] as $f) {
$registerTempFileForCleanup($f);
chmod($f, 0600);
/**
* Stream a SQL dump of schema and data into $sqlFile.
* - Tables first (DROP + CREATE + INSERTs)
* - Views (DROP VIEW + CREATE VIEW)
* - Triggers (DROP TRIGGER + CREATE TRIGGER)
*
* NOTE: Routines/events are not dumped here. Add if needed.
*/
function dump_database_streaming(mysqli $mysqli, string $sqlFile): void {
$fh = fopen($sqlFile, 'wb');
if (!$fh) {
http_response_code(500);
exit("Cannot open dump file");
}
// === 3. Generate SQL Dump
$sqlContent = "-- UTF-8 + Foreign Key Safe Dump\n";
$sqlContent .= "SET NAMES 'utf8mb4';\n";
$sqlContent .= "SET foreign_key_checks = 0;\n\n";
// Preamble
fwrite_ln($fh, "-- UTF-8 + Foreign Key Safe Dump");
fwrite_ln($fh, "SET NAMES 'utf8mb4';");
fwrite_ln($fh, "SET FOREIGN_KEY_CHECKS = 0;");
fwrite_ln($fh, "SET UNIQUE_CHECKS = 0;");
fwrite_ln($fh, "SET AUTOCOMMIT = 0;");
fwrite_ln($fh, "");
// Gather tables and views
$tables = [];
$res = $mysqli->query("SHOW TABLES");
$views = [];
$res = $mysqli->query("SHOW FULL TABLES");
if (!$res) {
error_log("MySQL Error: " . $mysqli->error);
fclose($fh);
error_log("MySQL Error (SHOW FULL TABLES): " . $mysqli->error);
http_response_code(500);
exit("Error retrieving tables.");
}
while ($row = $res->fetch_array(MYSQLI_NUM)) {
$name = $row[0];
$type = strtoupper($row[1] ?? '');
if ($type === 'VIEW') {
$views[] = $name;
} else {
$tables[] = $name;
}
}
$res->close();
while ($row = $res->fetch_row()) {
$tables[] = $row[0];
// --- TABLES: structure and data ---
foreach ($tables as $table) {
$createRes = $mysqli->query("SHOW CREATE TABLE `{$mysqli->real_escape_string($table)}`");
if (!$createRes) {
error_log("MySQL Error (SHOW CREATE TABLE $table): " . $mysqli->error);
// continue to next table
continue;
}
$createRow = $createRes->fetch_assoc();
$createSQL = array_values($createRow)[1] ?? '';
$createRes->close();
fwrite_ln($fh, "-- ----------------------------");
fwrite_ln($fh, "-- Table structure for `{$table}`");
fwrite_ln($fh, "-- ----------------------------");
fwrite_ln($fh, "DROP TABLE IF EXISTS `{$table}`;");
fwrite_ln($fh, $createSQL . ";");
fwrite_ln($fh, "");
// Dump data in a streaming fashion
$dataRes = $mysqli->query("SELECT * FROM `{$mysqli->real_escape_string($table)}`", MYSQLI_USE_RESULT);
if ($dataRes) {
$wroteHeader = false;
while ($row = $dataRes->fetch_assoc()) {
if (!$wroteHeader) {
fwrite_ln($fh, "-- Dumping data for table `{$table}`");
$wroteHeader = true;
}
$cols = array_map(fn($c) => '`' . $mysqli->real_escape_string($c) . '`', array_keys($row));
$vals = array_map(
function ($v) use ($mysqli) {
return is_null($v) ? "NULL" : "'" . $mysqli->real_escape_string($v) . "'";
},
array_values($row)
);
fwrite_ln($fh, "INSERT INTO `{$table}` (" . implode(", ", $cols) . ") VALUES (" . implode(", ", $vals) . ");");
}
$dataRes->close();
if ($wroteHeader) fwrite_ln($fh, "");
}
}
foreach ($tables as $table) {
$createRes = $mysqli->query("SHOW CREATE TABLE `$table`");
if (!$createRes) {
error_log("MySQL Error: " . $mysqli->error);
// --- VIEWS ---
foreach ($views as $view) {
$escView = $mysqli->real_escape_string($view);
$cRes = $mysqli->query("SHOW CREATE VIEW `{$escView}`");
if ($cRes) {
$row = $cRes->fetch_assoc();
$createView = $row['Create View'] ?? '';
$cRes->close();
fwrite_ln($fh, "-- ----------------------------");
fwrite_ln($fh, "-- View structure for `{$view}`");
fwrite_ln($fh, "-- ----------------------------");
fwrite_ln($fh, "DROP VIEW IF EXISTS `{$view}`;");
// Ensure statement ends with semicolon
if (!str_ends_with($createView, ';')) $createView .= ';';
fwrite_ln($fh, $createView);
fwrite_ln($fh, "");
}
}
// --- TRIGGERS ---
$tRes = $mysqli->query("SHOW TRIGGERS");
if ($tRes) {
while ($t = $tRes->fetch_assoc()) {
$triggerName = $t['Trigger'];
$escTrig = $mysqli->real_escape_string($triggerName);
$crt = $mysqli->query("SHOW CREATE TRIGGER `{$escTrig}`");
if ($crt) {
$row = $crt->fetch_assoc();
$createTrig = $row['SQL Original Statement'] ?? ($row['Create Trigger'] ?? '');
$crt->close();
fwrite_ln($fh, "-- ----------------------------");
fwrite_ln($fh, "-- Trigger for `{$triggerName}`");
fwrite_ln($fh, "-- ----------------------------");
fwrite_ln($fh, "DROP TRIGGER IF EXISTS `{$triggerName}`;");
if (!str_ends_with($createTrig, ';')) $createTrig .= ';';
fwrite_ln($fh, $createTrig);
fwrite_ln($fh, "");
}
}
$tRes->close();
}
// Postamble
fwrite_ln($fh, "SET FOREIGN_KEY_CHECKS = 1;");
fwrite_ln($fh, "SET UNIQUE_CHECKS = 1;");
fwrite_ln($fh, "COMMIT;");
fclose($fh);
}
/**
* Zip a folder to $zipFilePath, skipping symlinks and dot-entries.
*/
function zipFolderStrict(string $folderPath, string $zipFilePath): void {
$zip = new ZipArchive();
if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
error_log("Failed to open zip file: $zipFilePath");
http_response_code(500);
exit("Internal Server Error: Cannot open zip archive.");
}
$folderReal = realpath($folderPath);
if (!$folderReal || !is_dir($folderReal)) {
// Create an empty archive if uploads folder doesn't exist yet
$zip->close();
return;
}
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($folderReal, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
/** @var SplFileInfo $file */
if ($file->isDir()) continue;
if ($file->isLink()) continue; // skip symlinks
$filePath = $file->getRealPath();
if ($filePath === false) continue;
// ensure path is inside the folder boundary
if (strpos($filePath, $folderReal . DIRECTORY_SEPARATOR) !== 0 && $filePath !== $folderReal) {
continue;
}
$createRow = $createRes->fetch_assoc();
$createSQL = array_values($createRow)[1];
$sqlContent .= "\n-- ----------------------------\n";
$sqlContent .= "-- Table structure for `$table`\n";
$sqlContent .= "-- ----------------------------\n";
$sqlContent .= "DROP TABLE IF EXISTS `$table`;\n";
$sqlContent .= $createSQL . ";\n\n";
$dataRes = $mysqli->query("SELECT * FROM `$table`");
if ($dataRes && $dataRes->num_rows > 0) {
$sqlContent .= "-- Dumping data for table `$table`\n";
while ($row = $dataRes->fetch_assoc()) {
$columns = array_map(fn($col) => '`' . $mysqli->real_escape_string($col) . '`', array_keys($row));
$values = array_map(function ($val) use ($mysqli) {
return is_null($val) ? "NULL" : "'" . $mysqli->real_escape_string($val) . "'";
}, array_values($row));
$sqlContent .= "INSERT INTO `$table` (" . implode(", ", $columns) . ") VALUES (" . implode(", ", $values) . ");\n";
}
$sqlContent .= "\n";
}
$relativePath = substr($filePath, strlen($folderReal) + 1);
$zip->addFile($filePath, $relativePath);
}
$sqlContent .= "SET foreign_key_checks = 1;\n";
file_put_contents($sqlFile, $sqlContent);
$zip->close();
}
// === 4. Zip the uploads folder
$zipFolder("../uploads", $uploadsZip);
if (isset($_GET['download_backup'])) {
// === 5. Create version.txt
$commitHash = trim(shell_exec('git log -1 --format=%H')) ?: 'N/A';
$gitBranch = trim(shell_exec('git rev-parse --abbrev-ref HEAD')) ?: 'N/A';
validateCSRFToken($_GET['csrf_token']);
$versionContent = "ITFlow Backup Metadata\n";
$timestamp = date('YmdHis');
$baseName = "itflow_{$timestamp}";
$downloadName = $baseName . ".zip";
// === Scoped cleanup of temp files ===
$cleanupFiles = [];
$registerTempFileForCleanup = function ($file) use (&$cleanupFiles) {
$cleanupFiles[] = $file;
};
register_shutdown_function(function () use (&$cleanupFiles) {
foreach ($cleanupFiles as $file) {
if (is_file($file)) { @unlink($file); }
}
});
// === Create temp files ===
$sqlFile = tempnam(sys_get_temp_dir(), $baseName . "_sql_");
$uploadsZip = tempnam(sys_get_temp_dir(), $baseName . "_uploads_");
$versionFile = tempnam(sys_get_temp_dir(), $baseName . "_version_");
$finalZip = tempnam(sys_get_temp_dir(), $baseName . "_backup_");
foreach ([$sqlFile, $uploadsZip, $versionFile, $finalZip] as $f) {
$registerTempFileForCleanup($f);
@chmod($f, 0600);
}
// === Generate SQL Dump (streaming) ===
dump_database_streaming($mysqli, $sqlFile);
// === Zip the uploads folder (strict) ===
zipFolderStrict("../uploads", $uploadsZip);
// === Gather metadata & checksums ===
$commitHash = (function_exists('shell_exec') ? trim(shell_exec('git log -1 --format=%H 2>/dev/null')) : '') ?: 'N/A';
$gitBranch = (function_exists('shell_exec') ? trim(shell_exec('git rev-parse --abbrev-ref HEAD 2>/dev/null')) : '') ?: 'N/A';
$dbSha = hash_file('sha256', $sqlFile) ?: 'N/A';
$upSha = hash_file('sha256', $uploadsZip) ?: 'N/A';
$versionContent = "ITFlow Backup Metadata\n";
$versionContent .= "-----------------------------\n";
$versionContent .= "Generated: " . date('Y-m-d H:i:s') . "\n";
$versionContent .= "Backup File: " . basename($finalZip) . "\n";
$versionContent .= "Generated By: $session_name\n";
$versionContent .= "Backup File: " . $downloadName . "\n";
$versionContent .= "Generated By: " . ($session_name ?? 'Unknown User') . "\n";
$versionContent .= "Host: " . gethostname() . "\n";
$versionContent .= "Git Branch: $gitBranch\n";
$versionContent .= "Git Commit: $commitHash\n";
$versionContent .= "ITFlow Version: " . (defined('APP_VERSION') ? APP_VERSION : 'Unknown') . "\n";
$versionContent .= "Database Version: " . (defined('CURRENT_DATABASE_VERSION') ? CURRENT_DATABASE_VERSION : 'Unknown') . "\n";
$versionContent .= "Checksum (SHA256): \n";
$versionContent .= "Checksums (SHA256):\n";
$versionContent .= " db.sql: $dbSha\n";
$versionContent .= " uploads.zip: $upSha\n";
file_put_contents($versionFile, $versionContent);
@chmod($versionFile, 0600);
// === 6. Build final ZIP
// === Build final ZIP ===
$final = new ZipArchive();
if ($final->open($finalZip, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
error_log("Failed to create final zip: $finalZip");
http_response_code(500);
exit("Internal Server Error: Unable to create backup archive.");
}
$final->addFile($sqlFile, "db.sql");
$final->addFile($uploadsZip, "uploads.zip");
$final->addFile($versionFile, "version.txt");
$final->close();
chmod($finalZip, 0600);
@chmod($finalZip, 0600);
$checksum = hash_file('sha256', $finalZip);
file_put_contents($versionFile, $versionContent . "$checksum\n");
// === 7. Serve final ZIP
// === Serve final ZIP with a stable filename ===
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . basename($finalZip) . '"');
header('X-Content-Type-Options: nosniff');
header('Content-Disposition: attachment; filename="' . $downloadName . '"');
header('Content-Length: ' . filesize($finalZip));
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
// Push file
flush();
$fp = fopen($finalZip, 'rb');
fpassthru($fp);
fclose($fp);
logAction("System", "Backup Download", "$session_name downloaded full backup.");
// Log + UX
logAction("System", "Backup Download", ($session_name ?? 'Unknown User') . " downloaded full backup.");
flash_alert("Full backup downloaded.");
exit;
}
if (isset($_POST['backup_master_key'])) {
validateCSRFToken($_POST['csrf_token']);

View File

@@ -0,0 +1,157 @@
<?php
/*
* ITFlow - GET/POST request handler for Contract Templates
*/
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
if (isset($_POST['add_contract_template'])) {
// Sanitize text inputs
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$type = sanitizeInput($_POST['type']);
$renewal_frequency = sanitizeInput($_POST['renewal_frequency']);
$support_hours = sanitizeInput($_POST['support_hours']);
$details = mysqli_escape_string($mysqli, $_POST['details']);
// Numeric fields cast to integer
$sla_low_resp = intval($_POST['sla_low_response_time']);
$sla_med_resp = intval($_POST['sla_medium_response_time']);
$sla_high_resp = intval($_POST['sla_high_response_time']);
$sla_low_res = intval($_POST['sla_low_resolution_time']);
$sla_med_res = intval($_POST['sla_medium_resolution_time']);
$sla_high_res = intval($_POST['sla_high_resolution_time']);
$rate_standard = intval($_POST['rate_standard']);
$rate_after_hours = intval($_POST['hourly_rate_after_hours']);
$net_terms = intval($_POST['net_terms']);
// Insert into database (numbers not quoted)
mysqli_query($mysqli, "
INSERT INTO contract_templates SET
contract_template_name = '$name',
contract_template_description = '$description',
contract_template_details = '$details',
contract_template_type = '$type',
contract_template_renewal_frequency = '$renewal_frequency',
contract_template_sla_low_response_time = $sla_low_resp,
contract_template_sla_medium_response_time = $sla_med_resp,
contract_template_sla_high_response_time = $sla_high_resp,
contract_template_sla_low_resolution_time = $sla_low_res,
contract_template_sla_medium_resolution_time = $sla_med_res,
contract_template_sla_high_resolution_time = $sla_high_res,
contract_template_rate_standard = $rate_standard,
contract_template_rate_after_hours = $rate_after_hours,
contract_template_support_hours = '$support_hours',
contract_template_net_terms = $net_terms
");
$contract_template_id = mysqli_insert_id($mysqli);
// Log action
logAction("Contract Template", "Create", "$session_name created contract template $name", 0, $contract_template_id);
// Flash message
flash_alert("Contract Template <strong>$name</strong> created");
// Redirect back
redirect();
}
if (isset($_POST['edit_contract_template'])) {
$contract_template_id = intval($_POST['contract_template_id']);
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$type = sanitizeInput($_POST['type']);
$renewal_frequency= sanitizeInput($_POST['renewal_frequency']);
$support_hours = sanitizeInput($_POST['support_hours']);
$details = mysqli_escape_string($mysqli, $_POST['details']);
$sla_low_resp = intval($_POST['sla_low_response_time']);
$sla_med_resp = intval($_POST['sla_medium_response_time']);
$sla_high_resp = intval($_POST['sla_high_response_time']);
$sla_low_res = intval($_POST['sla_low_resolution_time']);
$sla_med_res = intval($_POST['sla_medium_resolution_time']);
$sla_high_res = intval($_POST['sla_high_resolution_time']);
$rate_standard = intval($_POST['rate_standard']);
$rate_after_hours = intval($_POST['rate_after_hours']);
$net_terms = intval($_POST['net_terms']);
mysqli_query($mysqli, "
UPDATE contract_templates SET
contract_template_name = '$name',
contract_template_description = '$description',
contract_template_details = '$details',
contract_template_type = '$type',
contract_template_renewal_frequency = '$renewal_frequency',
contract_template_sla_low_response_time = $sla_low_resp,
contract_template_sla_medium_response_time = $sla_med_resp,
contract_template_sla_high_response_time = $sla_high_resp,
contract_template_sla_low_resolution_time = $sla_low_res,
contract_template_sla_medium_resolution_time = $sla_med_res,
contract_template_sla_high_resolution_time = $sla_high_res,
contract_template_rate_standard = $rate_standard,
contract_template_rate_after_hours = $rate_after_hours,
contract_template_support_hours = '$support_hours',
contract_template_net_terms = $net_terms
WHERE contract_template_id = $contract_template_id
");
// Log action
logAction("Contract Template", "Update", "$session_name updated contract template $name", 0, $contract_template_id);
// Flash + redirect
flash_alert("Contract Template <strong>$name</strong> updated");
redirect();
}
if (isset($_GET['archive_contract_template'])) {
$contract_template_id = intval($_GET['archive_contract_template']);
$name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name');
mysqli_query($mysqli, "
UPDATE contract_templates SET contract_template_archived_at = NOW()
WHERE contract_template_id = $contract_template_id
LIMIT 1
");
logAction("Contract Template", "Archive", "$session_name archived contract template $name", 0, $contract_template_id);
flash_alert("Contract Template <strong>$name</strong> archived", "danger");
redirect();
}
if (isset($_GET['restore_contract_template'])) {
$contract_template_id = intval($_GET['restore_contract_template']);
$name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name');
mysqli_query($mysqli, "
UPDATE contract_templates SET contract_template_archived_at = NULL
WHERE contract_template_id = $contract_template_id
LIMIT 1
");
logAction("Contract Template", "Restore", "$session_name restored contract template $name", 0, $contract_template_id);
flash_alert("Contract Template <strong>$name</strong> restored");
redirect();
}
if (isset($_GET['delete_contract_template'])) {
$contract_template_id = intval($_GET['delete_contract_template']);
$name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name');
mysqli_query($mysqli, "
DELETE FROM contract_templates
WHERE contract_template_id = $contract_template_id
LIMIT 1
");
logAction("Contract Template", "Delete", "$session_name deleted contract template $name", 0, $contract_template_id);
flash_alert("Contract Template <strong>$name</strong> deleted", "danger");
redirect();
}
?>

View File

@@ -8,12 +8,24 @@ if (isset($_POST['add_document_template'])) {
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$content = mysqli_real_escape_string($mysqli,$_POST['content']);
mysqli_query($mysqli,"INSERT INTO document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '$content', document_template_created_by = $session_user_id");
mysqli_query($mysqli,"INSERT INTO document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '', document_template_created_by = $session_user_id");
$document_template_id = mysqli_insert_id($mysqli);
$processed_content = mysqli_escape_string(
$mysqli,
saveBase64Images(
$_POST['content'],
$_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/",
"uploads/document_templates/",
$document_template_id
)
);
// Document template update content
mysqli_query($mysqli,"UPDATE document_templates SET document_template_content = '$processed_content' WHERE document_template_id = $document_template_id");
logAction("Document Template", "Create", "$session_name created document template $name", 0, $document_template_id);
flash_alert("Document template <strong>$name</strong> created");
@@ -27,10 +39,25 @@ if (isset($_POST['edit_document_template'])) {
$document_template_id = intval($_POST['document_template_id']);
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$content = mysqli_real_escape_string($mysqli,$_POST['content']);
$processed_content = saveBase64Images(
$_POST['content'],
$_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/",
"uploads/document_templates/",
$document_template_id
);
$processed_content_escaped = mysqli_escape_string($mysqli, $processed_content);
// CLEAN UP unused images
cleanupUnusedImages(
$processed_content,
$_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/" . $document_template_id,
"/uploads/document_templates/" . $document_template_id
);
// Document edit query
mysqli_query($mysqli,"UPDATE document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '$content', document_template_updated_by = $session_user_id WHERE document_template_id = $document_template_id");
mysqli_query($mysqli,"UPDATE document_templates SET document_template_name = '$name', document_template_description = '$description', document_template_content = '$processed_content_escaped', document_template_updated_by = $session_user_id WHERE document_template_id = $document_template_id");
logAction("Document Template", "Edit", "$session_name edited document template $name", 0, $document_template_id);
@@ -48,6 +75,9 @@ if (isset($_GET['delete_document_template'])) {
mysqli_query($mysqli,"DELETE FROM document_templates WHERE document_template_id = $document_template_id");
// Delete uploads/document_templates/$document_template_id if exists
removeDirectory($_SERVER['DOCUMENT_ROOT'] . "/uploads/document_templates/" . $document_template_id);
logAction("Document Template", "Delete", "$session_name deleted document template $document_template_name");
flash_alert("Document Template <strong>$document_template_name</strong> deleted", 'error');

View File

@@ -10,10 +10,17 @@ if (isset($_POST['add_payment_method'])) {
validateCSRFToken($_POST['csrf_token']);
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$name = cleanInput($_POST['name']);
$description = cleanInput($_POST['description']);
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = '$name', payment_method_description = '$description'");
$query = mysqli_prepare(
$mysqli, "INSERT INTO payment_methods
SET payment_method_name = ?, payment_method_description = ?"
);
mysqli_stmt_bind_param($query, "ss", $name, $description);
mysqli_stmt_execute($query);
logAction("Payment Method", "Create", "$session_name created Payment Method $name");
@@ -26,12 +33,21 @@ if (isset($_POST['add_payment_method'])) {
if (isset($_POST['edit_payment_method'])) {
validateCSRFToken($_POST['csrf_token']);
$payment_method_id = intval($_POST['payment_method_id']);
$name = sanitizeInput($_POST['name']);
$description = sanitizeInput($_POST['description']);
$name = cleanInput($_POST['name']);
$description = cleanInput($_POST['description']);
mysqli_query($mysqli,"UPDATE payment_methods SET payment_method_name = '$name', payment_method_description = '$description' WHERE payment_method_id = $payment_method_id");
$query = mysqli_prepare(
$mysqli,
"UPDATE payment_methods
SET payment_method_name = ?, payment_method_description = ?
WHERE payment_method_id = ?"
);
mysqli_stmt_bind_param($query, "ssi", $name, $description, $payment_method_id);
mysqli_stmt_execute($query);
logAction("Payment Method", "Edit", "$session_name edited Payment Method $name");

View File

@@ -14,53 +14,20 @@ if (isset($_POST['add_payment_provider'])) {
$public_key = sanitizeInput($_POST['public_key']);
$private_key = sanitizeInput($_POST['private_key']);
$threshold = floatval($_POST['threshold']);
$enable_expense = intval($_POST['enable_expense'] ?? 0);
$account = intval($_POST['account']);
$expense_vendor = intval($_POST['expense_vendor']) ?? 0;
$expense_category = intval($_POST['expense_category']) ?? 0;
$percentage_fee = floatval($_POST['percentage_fee']) / 100 ?? 0;
$flat_fee = floatval($_POST['flat_fee']) ?? 0;
// Check to ensure provider isn't added twice
$sql = "SELECT 1 FROM payment_providers WHERE payment_provider_name = '$provider' LIMIT 1";
$result = mysqli_query($mysqli, $sql);
if (mysqli_num_rows($result) > 0) {
$sql = mysqli_query($mysqli, "SELECT 1 FROM payment_providers WHERE payment_provider_name = '$provider' LIMIT 1");
if (mysqli_num_rows($sql) > 0) {
flash_alert("Payment Provider <strong>$provider</strong> already exists", 'error');
redirect();
}
// Check for Stripe Account, if not create it
$sql_account = mysqli_query($mysqli,"SELECT account_id FROM accounts WHERE account_name = '$provider' AND account_archived_at IS NULL LIMIT 1");
if (mysqli_num_rows($sql_account) == 0) {
$account_id = mysqli_insert_id($mysqli);
} else {
$row = mysqli_fetch_array($sql_account);
$account_id = intval($row['account_id']);
}
// Expense defaults
$category_id = 0;
$vendor_id = 0;
if ($enable_expense) {
// Category
$sql_category = mysqli_query($mysqli,"SELECT category_id FROM categories WHERE category_name = 'Payment Processing' AND category_type = 'Expense' AND category_archived_at IS NULL LIMIT 1");
if (mysqli_num_rows($sql_category) == 0) {
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Processing Fee', category_type = 'Payment Processing', category_color = 'gray'");
$category_id = mysqli_insert_id($mysqli);
} else {
$row = mysqli_fetch_array($sql_category);
$category_id = intval($row['category_id']);
}
// Vendor
$sql_vendor = mysqli_query($mysqli,"SELECT vendor_id FROM vendors WHERE vendor_name = '$provider' AND vendor_client_id = 0 AND vendor_archived_at IS NULL LIMIT 1");
if (mysqli_num_rows($sql_vendor) == 0) {
mysqli_query($mysqli,"INSERT INTO vendors SET vendor_name = '$provider', vendor_description = 'Payment Processor Provider', vendor_client_id = 0");
$vendor_id = mysqli_insert_id($mysqli);
} else {
$row = mysqli_fetch_array($sql_vendor);
$vendor_id = intval($row['vendor_id']);
}
}
mysqli_query($mysqli,"INSERT INTO payment_providers SET payment_provider_name = '$provider', payment_provider_public_key = '$public_key', payment_provider_private_key = '$private_key', payment_provider_threshold = $threshold, payment_provider_account = $account_id, payment_provider_expense_vendor = $vendor_id, payment_provider_expense_category = $category_id, payment_provider_expense_percentage_fee = $percentage_fee, payment_provider_expense_flat_fee = $flat_fee");
mysqli_query($mysqli,"INSERT INTO payment_providers SET payment_provider_name = '$provider', payment_provider_public_key = '$public_key', payment_provider_private_key = '$private_key', payment_provider_threshold = $threshold, payment_provider_account = $account, payment_provider_expense_vendor = $expense_vendor, payment_provider_expense_category = $expense_category, payment_provider_expense_percentage_fee = $percentage_fee, payment_provider_expense_flat_fee = $flat_fee");
$provider_id = mysqli_insert_id($mysqli);
@@ -81,11 +48,13 @@ if (isset($_POST['edit_payment_provider'])) {
$public_key = sanitizeInput($_POST['public_key']);
$private_key = sanitizeInput($_POST['private_key']);
$threshold = floatval($_POST['threshold']);
$enable_expense = intval($_POST['enable_expense'] ?? 0);
$account = intval($_POST['account']);
$expense_vendor = intval($_POST['expense_vendor']) ?? 0;
$expense_category = intval($_POST['expense_category']) ?? 0;
$percentage_fee = floatval($_POST['percentage_fee']) / 100;
$flat_fee = floatval($_POST['flat_fee']);
mysqli_query($mysqli,"UPDATE payment_providers SET payment_provider_public_key = '$public_key', payment_provider_private_key = '$private_key', payment_provider_threshold = $threshold, payment_provider_expense_percentage_fee = $percentage_fee, payment_provider_expense_flat_fee = $flat_fee WHERE payment_provider_id = $provider_id");
mysqli_query($mysqli,"UPDATE payment_providers SET payment_provider_public_key = '$public_key', payment_provider_private_key = '$private_key', payment_provider_threshold = $threshold, payment_provider_account = $account, payment_provider_expense_vendor = $expense_vendor, payment_provider_expense_category = $expense_category, payment_provider_expense_percentage_fee = $percentage_fee, payment_provider_expense_flat_fee = $flat_fee WHERE payment_provider_id = $provider_id");
logAction("Payment Provider", "Edit", "$session_name edited Payment Provider $provider");
@@ -98,9 +67,14 @@ if (isset($_POST['edit_payment_provider'])) {
if (isset($_GET['delete_payment_provider'])) {
validateCSRFToken($_GET['csrf_token']);
$provider_id = intval($_GET['delete_payment_provider']);
// When deleted it cascades deletes
// all Recurring paymentes related to payment provider
// Delete all Saved Cards related
// Delete Client Payment Provider Releation
$provider_name = sanitizeInput(getFieldById('payment_providers', $provider_id, 'provider_name'));
// Delete provider

View File

@@ -42,7 +42,7 @@ if (isset($_GET['delete_saved_payment'])) {
try {
// Initialize stripe
require_once 'plugins/stripe-php/init.php';
require_once '../plugins/stripe-php/init.php';
$stripe = new \Stripe\StripeClient($private_key);
// Detach PM
@@ -56,7 +56,7 @@ if (isset($_GET['delete_saved_payment'])) {
}
// Remove payment method from ITFlow
// Remove payment method from ITFlow. This will also cascade delete related recurring payments setup
mysqli_query($mysqli, "DELETE FROM client_saved_payment_methods WHERE saved_payment_id = $saved_payment_id");
// SQL Cascade delete will Remove All Associated Auto Payment Methods on recurring invoices in the recurring payments table.

View File

@@ -150,7 +150,7 @@ if (isset($_POST['test_email_smtp'])) {
$mail = addToMailQueue($data);
if ($mail === true) {
flash_alert("Test email queued! <a class='text-bold text-light' href='admin_mail_queue.php'>Check Admin > Mail queue</a>");
flash_alert("Test email queued! <a class='text-bold text-light' href='mail_queue.php'>Check Admin > Mail queue</a>");
} else {
flash_alert("Failed to add test mail to queue", 'error');
}
@@ -160,27 +160,128 @@ if (isset($_POST['test_email_smtp'])) {
}
if (isset($_POST['test_email_imap'])) {
validateCSRFToken($_POST['csrf_token']);
// Setup your IMAP connection parameters
$hostname = "{" . $config_imap_host . ":" . $config_imap_port . "/" . $config_imap_encryption . "/novalidate-cert}INBOX";
$username = $config_imap_username;
$password = $config_imap_password;
$host = $config_imap_host;
$port = (int) $config_imap_port;
$encryption = strtolower(trim($config_imap_encryption)); // e.g. "ssl", "tls", "none"
$username = $config_imap_username;
$password = $config_imap_password;
// Build remote socket (implicit SSL vs plain TCP)
$transport = 'tcp';
if ($encryption === 'ssl') {
$transport = 'ssl';
}
$remote_socket = $transport . '://' . $host . ':' . $port;
// Stream context (you can tighten these if you want strict validation)
$contextOptions = [];
if (in_array($encryption, ['ssl', 'tls'], true)) {
$contextOptions['ssl'] = [
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true,
];
}
$context = stream_context_create($contextOptions);
try {
$inbox = @imap_open($hostname, $username, $password);
$errno = 0;
$errstr = '';
if ($inbox) {
imap_close($inbox);
// 10-second timeout, adjust as needed
$fp = @stream_socket_client(
$remote_socket,
$errno,
$errstr,
10,
STREAM_CLIENT_CONNECT,
$context
);
if (!$fp) {
throw new Exception("Could not connect to IMAP server: [$errno] $errstr");
}
stream_set_timeout($fp, 10);
// Read server greeting (IMAP servers send something like: * OK Dovecot ready)
$greeting = fgets($fp, 1024);
if ($greeting === false || strpos($greeting, '* OK') !== 0) {
fclose($fp);
throw new Exception("Invalid IMAP greeting: " . trim((string) $greeting));
}
// If you really want STARTTLS for "tls" (port 143), you can do it here
if ($encryption === 'tls' && stripos($greeting, 'STARTTLS') !== false) {
// Request STARTTLS
fwrite($fp, "A0001 STARTTLS\r\n");
$line = fgets($fp, 1024);
if ($line === false || stripos($line, 'A0001 OK') !== 0) {
fclose($fp);
throw new Exception("STARTTLS failed: " . trim((string) $line));
}
// Enable crypto on the stream
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
fclose($fp);
throw new Exception("Unable to enable TLS encryption on IMAP connection.");
}
}
// --- Do LOGIN command ---
$tag = 'A0002';
// Simple quoting; this may fail with some special chars in username/password.
$loginCmd = sprintf(
"%s LOGIN \"%s\" \"%s\"\r\n",
$tag,
addcslashes($username, "\\\""),
addcslashes($password, "\\\"")
);
fwrite($fp, $loginCmd);
$success = false;
$errorLine = '';
while (!feof($fp)) {
$line = fgets($fp, 2048);
if ($line === false) {
break;
}
// Look for tagged response for our LOGIN
if (strpos($line, $tag . ' ') === 0) {
if (stripos($line, $tag . ' OK') === 0) {
$success = true;
} else {
$errorLine = trim($line);
}
break;
}
}
// Always logout / close
fwrite($fp, "A0003 LOGOUT\r\n");
fclose($fp);
if ($success) {
flash_alert("Connected successfully");
} else {
throw new Exception(imap_last_error());
if (!$errorLine) {
$errorLine = 'Unknown IMAP authentication error';
}
throw new Exception($errorLine);
}
} catch (Exception $e) {
flash_alert("<strong>IMAP connection failed:</strong> " . $e->getMessage(), 'error');
flash_alert("<strong>IMAP connection failed:</strong> " . htmlspecialchars($e->getMessage()), 'error');
}
redirect();
}

View File

@@ -49,3 +49,17 @@ if (isset($_POST['edit_favicon_settings'])) {
redirect();
}
if (isset($_GET['reset_favicon'])) {
if (file_exists("../uploads/favicon.ico")) {
unlink("../uploads/favicon.ico");
}
logAction("Settings", "Edit", "$session_name reset Favicon");
flash_alert("Favicon reset", 'error');
redirect();
}

View File

@@ -28,7 +28,7 @@ if (isset($_POST['edit_tag'])) {
$tag_id = intval($_POST['tag_id']);
mysqli_query($mysqli,"UPDATE tags SET tag_name = '$name', tag_type = $type, tag_color = '$color', tag_icon = '$icon' WHERE tag_id = $tag_id");
mysqli_query($mysqli,"UPDATE tags SET tag_name = '$name', tag_color = '$color', tag_icon = '$icon' WHERE tag_id = $tag_id");
logAction("Tag", "Edit", "$session_name edited tag $name", 0, $tag_id);

View File

@@ -22,7 +22,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-project-diagram mr-2"></i>Project Templates</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addProjectTemplateModal"><i class="fas fa-plus mr-2"></i>New Project Template</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/project_template/project_template_add.php"><i class="fas fa-plus mr-2"></i>New Project Template</button>
</div>
</div>
<div class="card-body">
@@ -87,7 +87,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<tr>
<td>
<a class="text-dark" href="#" data-toggle="modal" data-target="#editProjectTemplateModal<?php echo $project_template_id; ?>">
<a class="text-dark ajax-modal" href="#" data-modal-url="modals/project_template/project_template_edit.php?project_template_id=<?= $project_template_id ?>">
<div class="media">
<i class="fa fa-fw fa-2x fa-project-diagram mr-3"></i>
<div class="media-body">
@@ -109,7 +109,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#editProjectTemplateModal<?php echo $project_template_id; ?>">
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/project_template/project_template_edit.php?project_template_id=<?= $project_template_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<?php if($session_user_role == 3) { ?>
@@ -123,10 +123,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</td>
</tr>
<?php
require "modals/project_template/project_template_edit.php";
<?php
}
?>
@@ -134,12 +132,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php";
?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<?php
require_once "modals/project_template/project_template_add.php";
require_once "../includes/footer.php";

View File

@@ -13,9 +13,9 @@ if (isset($_GET['project_template_id'])) {
);
if (mysqli_num_rows($sql_project_templates) == 0) {
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='admin_project_template.php'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='javascript:history.back()'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
include_once "footer.php";
require_once "../includes/footer.php";
exit;
}
@@ -91,7 +91,7 @@ if (isset($_GET['project_template_id'])) {
<div class="col-sm-2">
<div class="btn-group float-right">
<button type="button" class="btn btn-primary btn-sm" href="#" data-toggle="modal" data-target="#addProjectTemplateTicketTemplateModal">
<button type="button" class="btn btn-primary btn-sm ajax-modal" href="#" data-modal-url="modals/project_template/project_template_ticket_template_add.php?project_template_id=<?= $project_template_id ?>">
<i class="fas fa-fw fa-plus mr-2"></i>Add Ticket Template
</button>
<div class="dropdown dropleft text-center ml-3">
@@ -99,7 +99,7 @@ if (isset($_GET['project_template_id'])) {
<i class="fas fa-fw fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#editProjectTemplateModal<?php echo $project_template_id; ?>">
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/project_template/project_template_edit.php?project_template_id=<?= $project_template_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit Template
</a>
<?php if ($session_user_role == 3) { ?>
@@ -221,9 +221,6 @@ if (isset($_GET['project_template_id'])) {
<?php
require_once "modals/project_template/project_template_edit.php";
require_once "modals/project_template/project_template_ticket_template_add.php";
}
require_once "../includes/footer.php";

View File

@@ -24,7 +24,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<h3 class="card-title mt-2"><i class="fas fa-fw fa-user-shield mr-2"></i>Roles</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addRoleModal">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/role/role_add.php">
<i class="fas fa-fw fa-user-plus mr-2"></i>New Role
</button>
</div>
@@ -143,6 +143,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<?php
require_once "modals/role/role_add.php";
require_once "../includes/footer.php";

View File

@@ -13,18 +13,18 @@ $sql = mysqli_query($mysqli, "
clients.client_name,
client_payment_provider.payment_provider_client
FROM client_saved_payment_methods
LEFT JOIN payment_providers
LEFT JOIN payment_providers
ON client_saved_payment_methods.saved_payment_provider_id = payment_providers.payment_provider_id
LEFT JOIN clients
LEFT JOIN clients
ON client_saved_payment_methods.saved_payment_client_id = clients.client_id
LEFT JOIN client_payment_provider
ON client_payment_provider.client_id = client_saved_payment_methods.saved_payment_client_id
AND client_payment_provider.payment_provider_id = client_saved_payment_methods.saved_payment_provider_id
WHERE
client_name LIKE '%$q%'
OR payment_provider_name LIKE '%$q%'
OR saved_payment_description LIKE '%$q%'
OR payment_provider_client LIKE '%$q%'
WHERE
client_name LIKE '%$q%'
OR payment_provider_name LIKE '%$q%'
OR saved_payment_description LIKE '%$q%'
OR payment_provider_client LIKE '%$q%'
OR saved_payment_provider_method LIKE '%$q%'
ORDER BY $sort $order
");
@@ -33,6 +33,16 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<ol class="breadcrumb d-print-none">
<li class="breadcrumb-item">
<a href="/admin">Admin</a>
</li>
<li class="breadcrumb-item">
<a href="payment_provider.php">Payment Providers</a>
</li>
<li class="breadcrumb-item active">Saved Payment Methods (Stripe)</li>
</ol>
<div class="card card-dark">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-fw fa-credit-card mr-2"></i>Saved Payment Methods</h3>
@@ -107,8 +117,16 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<tr>
<td><?php echo $client_name; ?> (<?php echo $client_id; ?>)</td>
<td><?php echo $provider_name; ?> (<?php echo $provider_id; ?>)</td>
<td>
<?= $client_name ?>
<br>
<small class="text-secondary">ID: <?= $client_id ?></small>
</td>
<td>
<?= $provider_name ?>
<br>
<small class="text-secondary">ID: <?= $provider_id ?></small>
</td>
<td><?php echo $saved_payment_description; ?></td>
<td><?php echo $provider_client; ?></td>
<td><?php echo $provider_payment_method; ?></td>

View File

@@ -214,7 +214,7 @@ require_once "includes/inc_all_admin.php";
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="hourly_rate" value="<?php echo number_format($config_default_hourly_rate, 2, '.', ''); ?>" placeholder="0.00" required>
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="hourly_rate" value="<?php echo number_format($config_default_hourly_rate, 2, '.', ''); ?>" placeholder="0.00" required>
</div>
</div>

View File

@@ -57,11 +57,12 @@ require_once "includes/inc_all_admin.php";
<hr>
<button type="submit" name="edit_favicon_settings" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Upload Icon</button>
<?php if(file_exists("../uploads/favicon.ico")) { ?>
<a href="post.php?reset_favicon" class="btn btn-outline-danger"><i class="fas fa-redo-alt mr-2"></i>Reset Favicon</a>
<?php } ?>
</form>
</div>
</div>
<?php
require_once "../includes/footer.php";

View File

@@ -21,7 +21,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-cube mr-2"></i>License Templates</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addSoftwareTemplateModal"><i class="fas fa-plus mr-2"></i>New License Template</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/software_template/software_template_add.php"><i class="fas fa-plus mr-2"></i>New License Template</button>
</div>
</div>
<div class="card-body">
@@ -127,5 +127,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<?php
require_once "modals/software_template/software_template_add.php";
require_once "../includes/footer.php";

View File

@@ -6,10 +6,31 @@ $order = "ASC";
require_once "includes/inc_all_admin.php";
if (isset($_GET['type'])) {
$type_filter = intval($_GET['type']);
} else {
$type_filter = 1;
}
if ($type_filter == 1) {
$tag_type_display = "Client";
} elseif ( $type_filter == 2) {
$tag_type_display = "Location";
} elseif ( $type_filter == 3) {
$tag_type_display = "Contact";
} elseif ( $type_filter == 4) {
$tag_type_display = "Credential";
} elseif ( $type_filter == 5) {
$tag_type_display = "Asset";
} else {
$tag_type_display = "Unknown";
}
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM tags
WHERE tag_name LIKE '%$q%'
AND tag_type = $type_filter
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
@@ -19,9 +40,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-tags mr-2"></i>Tags</h3>
<h3 class="card-title mt-2"><i class="fas fa-fw fa-tags mr-2"></i><?= $tag_type_display ?> Tags</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tag/tag_add.php"><i class="fas fa-plus mr-2"></i>New Tag</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tag/tag_add.php?type=<?= $type_filter ?>"><i class="fas fa-plus mr-2"></i>New <?= $tag_type_display ?> Tag</button>
</div>
</div>
@@ -30,7 +51,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="col-sm-4 mb-2">
<form autocomplete="off">
<div class="input-group">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Tags">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search <?= $tag_type_display ?> Tags">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
@@ -38,6 +59,45 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</form>
</div>
<div class="col-sm-8">
<div class="btn-group float-right">
<a href="?type=1"
class="btn <?php if ($type_filter == 1) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Client</a>
<a href="?type=2"
class="btn <?php if ($type_filter == 2) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Location</a>
<a href="?type=3"
class="btn <?php if ($type_filter == 3) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Contact</a>
<a href="?type=4"
class="btn <?php if ($type_filter == 4) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Credential</a>
<a href="?type=5"
class="btn <?php if ($type_filter == 5) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Asset</a>
<a href="?<?= $url_query_strings_sort ?>&archived=1"
class="btn <?php if (isset($_GET['archived'])) {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>"><i
class="fas fa-fw fa-archive mr-2"></i>Archived</a>
</div>
</div>
</div>
@@ -51,11 +111,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
Name <?php if ($sort == 'tag_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tag_type&order=<?php echo $disp; ?>">
Type <?php if ($sort == 'tag_type') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
@@ -65,18 +120,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
while ($row = mysqli_fetch_array($sql)) {
$tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']);
$tag_type = intval($row['tag_type']);
if ( $tag_type == 1) {
$tag_type_display = "Client Tag";
} elseif ( $tag_type == 2) {
$tag_type_display = "Location Tag";
} elseif ( $tag_type == 3) {
$tag_type_display = "Contact Tag";
} elseif ( $tag_type == 4) {
$tag_type_display = "Credential Tag";
} else {
$tag_type_display = "Unknown Tag";
}
$tag_color = nullable_htmlentities($row['tag_color']);
$tag_icon = nullable_htmlentities($row['tag_icon']);
@@ -88,7 +131,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<span class='badge text-light p-2 mr-1' style="background-color: <?php echo $tag_color; ?>"><i class="fa fa-fw fa-<?php echo $tag_icon; ?> mr-2"></i><?php echo $tag_name; ?></span>
</a>
</td>
<td><?php echo $tag_type_display; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
@@ -117,8 +159,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php";
?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>

View File

@@ -17,84 +17,83 @@ $num_rows = mysqli_num_rows($sql);
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Taxes</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTaxModal"><i class="fas fa-plus mr-2"></i>New Tax</button>
</div>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tax_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'tax_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tax_percent&order=<?php echo $disp; ?>">
Percent <?php if ($sort == 'tax_percent') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$tax_id = intval($row['tax_id']);
$tax_name = nullable_htmlentities($row['tax_name']);
$tax_percent = floatval($row['tax_percent']);
?>
<tr>
<td>
<a class="text-dark text-bold ajax-modal" href="#"
data-modal-url="modals/tax/tax_edit.php?id=<?= $tax_id ?>">
<?php echo $tax_name; ?>
</a>
</td>
<td><?php echo "$tax_percent%"; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/tax/tax_edit.php?id=<?= $tax_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_tax=<?php echo $tax_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
</div>
</div>
</td>
</tr>
<?php
}
if ($num_rows == 0) {
echo "<h3 class='text-secondary mt-3' style='text-align: center'>No Records Here</h3>";
}
?>
</tbody>
</table>
</div>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Taxes</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tax/tax_add.php"><i class="fas fa-plus mr-2"></i>New Tax</button>
</div>
</div>
<div class="card-body">
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tax_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'tax_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tax_percent&order=<?php echo $disp; ?>">
Percent <?php if ($sort == 'tax_percent') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$tax_id = intval($row['tax_id']);
$tax_name = nullable_htmlentities($row['tax_name']);
$tax_percent = floatval($row['tax_percent']);
?>
<tr>
<td>
<a class="text-dark text-bold ajax-modal" href="#"
data-modal-url="modals/tax/tax_edit.php?id=<?= $tax_id ?>">
<?php echo $tax_name; ?>
</a>
</td>
<td><?php echo "$tax_percent%"; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/tax/tax_edit.php?id=<?= $tax_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_tax=<?php echo $tax_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
</div>
</div>
</td>
</tr>
<?php
}
if ($num_rows == 0) {
echo "<h3 class='text-secondary mt-3' style='text-align: center'>No Records Here</h3>";
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php
require_once "modals/tax/tax_add.php";
require_once "../includes/footer.php";

View File

@@ -21,7 +21,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-info-circle mr-2"></i>Tickets Statuses</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTicketStatusModal"><i class="fas fa-plus mr-2"></i>New Ticket Status</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/ticket_status/ticket_status_add.php"><i class="fas fa-plus mr-2"></i>New Ticket Status</button>
</div>
</div>
@@ -120,13 +120,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php";
?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<?php
require_once "modals/ticket_status/ticket_status_add.php";
require_once "../includes/footer.php";

View File

@@ -8,10 +8,15 @@ require_once "includes/inc_all_admin.php";
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM ticket_templates
WHERE (ticket_template_name LIKE '%$q%' OR ticket_template_description LIKE '%$q%')
AND ticket_template_archived_at IS NULL
ORDER BY $sort $order LIMIT $record_from, $record_to"
"SELECT SQL_CALC_FOUND_ROWS *,
COUNT(task_template_id) AS task_count
FROM ticket_templates
LEFT JOIN task_templates ON task_template_ticket_template_id = ticket_template_id
WHERE (ticket_template_name LIKE '%$q%' OR ticket_template_description LIKE '%$q%')
AND ticket_template_archived_at IS NULL
GROUP BY ticket_template_id
ORDER BY $sort $order
LIMIT $record_from, $record_to"
);
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
@@ -22,7 +27,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Templates</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTicketTemplateModal"><i class="fas fa-plus mr-2"></i>New Ticket Template</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/ticket_template/ticket_template_add.php" data-modal-size="lg"><i class="fas fa-plus mr-2"></i>New Ticket Template</button>
</div>
</div>
<div class="card-body">
@@ -46,14 +51,18 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<hr>
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if($num_rows[0] == 0){ echo "d-none"; } ?>">
<thead class="text-dark <?php if($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=ticket_template_name&order=<?php echo $disp; ?>">
<a class="text-secondary" href="?<?= $url_query_strings_sort ?>&sort=ticket_template_name&order=<?= $disp ?>">
Template <?php if ($sort == 'ticket_template_name') { echo $order_icon; } ?>
</a>
</th>
<th>Tasks</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=task_count&order=<?php echo $disp; ?>">
Tasks <?php if ($sort == 'task_count') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
@@ -66,6 +75,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$ticket_template_description = nullable_htmlentities($row['ticket_template_description']);
$ticket_template_subject = nullable_htmlentities($row['ticket_template_subject']);
$ticket_template_created_at = nullable_htmlentities($row['ticket_template_created_at']);
$task_count = intval($row['task_count']);
?>
<tr>
@@ -75,23 +85,23 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fa fa-fw fa-2x fa-life-ring mr-3"></i>
<div class="media-body">
<div>
<a href="ticket_template_details.php?ticket_template_id=<?php echo $ticket_template_id; ?>">
<?php echo $ticket_template_name; ?>
<a href="ticket_template_details.php?ticket_template_id=<?= $ticket_template_id ?>">
<?= $ticket_template_name ?>
</a>
</div>
<div><small class="text-secondary"><?php echo $ticket_template_description; ?></small></div>
<div><small class="text-secondary"><?= $ticket_template_description ?></small></div>
</div>
</div>
</a>
</td>
<td>0</td>
<td><?= $task_count ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_ticket_template=<?php echo $ticket_template_id; ?>">
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_ticket_template=<?= $ticket_template_id ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
</div>
@@ -110,6 +120,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<?php
require_once "modals/ticket_template/ticket_template_add.php";
require_once "../includes/footer.php";

View File

@@ -15,9 +15,15 @@ if (isset($_GET['ticket_template_id'])) {
$ticket_template_id = intval($_GET['ticket_template_id']);
}
$sql_ticket_templates = mysqli_query($mysqli, "SELECT * FROM ticket_templates WHERE ticket_template_id = $ticket_template_id");
$sql_ticket_template = mysqli_query($mysqli, "SELECT * FROM ticket_templates WHERE ticket_template_id = $ticket_template_id LIMIT 1");
$row = mysqli_fetch_array($sql_ticket_templates);
if (mysqli_num_rows($sql_ticket_template) == 0) {
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='javascript:history.back()'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
require_once "../includes/footer.php";
exit();
}
$row = mysqli_fetch_array($sql_ticket_template);
$ticket_template_name = nullable_htmlentities($row['ticket_template_name']);
$ticket_template_description = nullable_htmlentities($row['ticket_template_description']);

View File

@@ -26,16 +26,23 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<h3 class="card-title mt-2"><i class="fas fa-fw fa-users mr-2"></i>Users</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addUserModal">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/user/user_add.php">
<i class="fas fa-fw fa-user-plus mr-2"></i>New User
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<!--<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#userInviteModal"><i class="fas fa-paper-plane mr-2"></i>Invite User</a>-->
<!--<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/user/user_invite.php"><i class="fas fa-paper-plane mr-2"></i>Invite User</a>-->
<?php if ($num_rows[0] > 1) { ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportUserModal"><i class="fa fa-fw fa-download mr-2"></i>Export</a>
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/user/user_export.php">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="#" data-toggle="modal" data-target="#resetAllUserPassModal"><i class="fas fa-skull-crossbones mr-2"></i>IR</a>
<a class="dropdown-item text-danger ajax-modal" href="#"
data-modal-url="modals/user/user_all_reset_password.php"
data-modal-size="lg">
<i class="fas fa-skull-crossbones mr-2"></i>IR
</a>
<?php } ?>
</div>
</div>
@@ -54,7 +61,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<div class="col-md-8">
<div class="btn-group float-right">
<a href="?archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
<a href="?archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived
</a>
@@ -156,7 +163,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<tr>
<td class="text-center">
<a href="#"
<a href="#" title="UserID: <?= $user_id ?>"
<?php if ($user_id !== $session_user_id) { // Prevent modifying self ?>
class="ajax-modal"
data-modal-url="modals/user/user_edit.php?id=<?= $user_id ?>"
@@ -233,15 +240,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
</div>
</div>
<script>
function generatePassword() {
document.getElementById("password").value = "<?php echo randomString() ?>"
}
</script>
<?php
require_once "modals/user/user_add.php";
require_once "modals/user/user_invite.php";
require_once "modals/user/user_export.php";
require_once "modals/user/user_all_reset_password.php";
require_once "../includes/footer.php";
require_once "../includes/footer.php";

View File

@@ -16,153 +16,151 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2">
<i class="fas fa-fw fa-building mr-2"></i>Vendor Templates
</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addVendorTemplateModal">
<i class="fas fa-plus mr-2"></i>New Vendor Template
</button>
</div>
</div>
<div class="card-body">
<form autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Vendors Templates">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=vendor_template_name&order=<?php echo $disp; ?>">
Vendor <?php if ($sort == 'vendor_template_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=vendor_template_description&order=<?php echo $disp; ?>">
Description <?php if ($sort == 'vendor_template_description') { echo $order_icon; } ?>
</a>
</th>
<th>Contact</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$vendor_template_id = intval($row['vendor_template_id']);
$vendor_template_name = nullable_htmlentities($row['vendor_template_name']);
$vendor_template_description = nullable_htmlentities($row['vendor_template_description']);
if (empty($vendor_template_description)) {
$vendor_template_description_display = "-";
} else {
$vendor_template_description_display = $vendor_template_description;
}
$vendor_template_account_number = nullable_htmlentities($row['vendor_template_account_number']);
$vendor_template_contact_name = nullable_htmlentities($row['vendor_template_contact_name']);
if (empty($vendor_template_contact_name)) {
$vendor_template_contact_name_display = "-";
} else {
$vendor_template_contact_name_display = $vendor_template_contact_name;
}
$vendor_template_phone = formatPhoneNumber($row['vendor_template_phone']);
$vendor_template_extension = nullable_htmlentities($row['vendor_template_extension']);
$vendor_template_email = nullable_htmlentities($row['vendor_template_email']);
$vendor_template_website = nullable_htmlentities($row['vendor_template_website']);
$vendor_template_hours = nullable_htmlentities($row['vendor_template_hours']);
$vendor_template_sla = nullable_htmlentities($row['vendor_template_sla']);
$vendor_template_code = nullable_htmlentities($row['vendor_template_code']);
$vendor_template_notes = nullable_htmlentities($row['vendor_template_notes']);
?>
<tr>
<th>
<a class="text-dark ajax-modal" href="#"
data-modal-url="modals/vendor_template/vendor_template_edit.php?id=<?= $vendor_template_id ?>">
<i class="fa fa-fw fa-building text-secondary mr-2"></i><?php echo $vendor_template_name; ?>
</a>
<?php
if (!empty($vendor_template_account_number)) {
?>
<br>
<small class="text-secondary"><?php echo $vendor_template_account_number; ?></small>
<?php
}
?>
</th>
<td><?php echo $vendor_template_description_display; ?></td>
<td>
<?php
if (!empty($vendor_template_contact_name)) {
?>
<i class="fa fa-fw fa-user text-secondary mr-2 mb-2"></i><?php echo $vendor_template_contact_name_display; ?>
<br>
<?php
} else {
echo $vendor_template_contact_name_display;
}
if (!empty($vendor_template_phone)) { ?>
<i class="fa fa-fw fa-phone text-secondary mr-2 mb-2"></i><?php echo $vendor_template_phone; ?>
<br>
<?php }
if (!empty($vendor_template_email)) { ?>
<i class="fa fa-fw fa-envelope text-secondary mr-2 mb-2"></i><?php echo $vendor_template_email; ?>
<br>
<?php } ?>
</td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/vendor_template/vendor_template_edit.php?id=<?= $vendor_template_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_vendor=<?php echo $vendor_template_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php";
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2">
<i class="fas fa-fw fa-building mr-2"></i>Vendor Templates
</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/vendor_template/vendor_template_add.php">
<i class="fas fa-plus mr-2"></i>New Vendor Template
</button>
</div>
</div>
<div class="card-body">
<form autocomplete="off">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Vendors Templates">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=vendor_template_name&order=<?php echo $disp; ?>">
Vendor <?php if ($sort == 'vendor_template_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=vendor_template_description&order=<?php echo $disp; ?>">
Description <?php if ($sort == 'vendor_template_description') { echo $order_icon; } ?>
</a>
</th>
<th>Contact</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$vendor_template_id = intval($row['vendor_template_id']);
$vendor_template_name = nullable_htmlentities($row['vendor_template_name']);
$vendor_template_description = nullable_htmlentities($row['vendor_template_description']);
if (empty($vendor_template_description)) {
$vendor_template_description_display = "-";
} else {
$vendor_template_description_display = $vendor_template_description;
}
$vendor_template_account_number = nullable_htmlentities($row['vendor_template_account_number']);
$vendor_template_contact_name = nullable_htmlentities($row['vendor_template_contact_name']);
if (empty($vendor_template_contact_name)) {
$vendor_template_contact_name_display = "-";
} else {
$vendor_template_contact_name_display = $vendor_template_contact_name;
}
$vendor_template_phone = formatPhoneNumber($row['vendor_template_phone']);
$vendor_template_extension = nullable_htmlentities($row['vendor_template_extension']);
$vendor_template_email = nullable_htmlentities($row['vendor_template_email']);
$vendor_template_website = nullable_htmlentities($row['vendor_template_website']);
$vendor_template_hours = nullable_htmlentities($row['vendor_template_hours']);
$vendor_template_sla = nullable_htmlentities($row['vendor_template_sla']);
$vendor_template_code = nullable_htmlentities($row['vendor_template_code']);
$vendor_template_notes = nullable_htmlentities($row['vendor_template_notes']);
?>
<tr>
<th>
<a class="text-dark ajax-modal" href="#"
data-modal-url="modals/vendor_template/vendor_template_edit.php?id=<?= $vendor_template_id ?>">
<i class="fa fa-fw fa-building text-secondary mr-2"></i><?php echo $vendor_template_name; ?>
</a>
<?php
if (!empty($vendor_template_account_number)) {
?>
<br>
<small class="text-secondary"><?php echo $vendor_template_account_number; ?></small>
<?php
}
?>
</th>
<td><?php echo $vendor_template_description_display; ?></td>
<td>
<?php
if (!empty($vendor_template_contact_name)) {
?>
<i class="fa fa-fw fa-user text-secondary mr-2 mb-2"></i><?php echo $vendor_template_contact_name_display; ?>
<br>
<?php
} else {
echo $vendor_template_contact_name_display;
}
if (!empty($vendor_template_phone)) { ?>
<i class="fa fa-fw fa-phone text-secondary mr-2 mb-2"></i><?php echo $vendor_template_phone; ?>
<br>
<?php }
if (!empty($vendor_template_email)) { ?>
<i class="fa fa-fw fa-envelope text-secondary mr-2 mb-2"></i><?php echo $vendor_template_email; ?>
<br>
<?php } ?>
</td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/vendor_template/vendor_template_edit.php?id=<?= $vendor_template_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_vendor_template=<?= $vendor_template_id ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<?php
require_once "modals/vendor_template/vendor_template_add.php";
require_once "../includes/footer.php";

View File

@@ -25,7 +25,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-piggy-bank mr-2"></i>Accounts</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addAccountModal"><i class="fas fa-plus mr-2"></i>New Account</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/account/account_add.php"><i class="fas fa-plus mr-2"></i>New Account</button>
</div>
</div>
<div class="card-body">
@@ -123,6 +123,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<?php
require_once "modals/account/account_add.php";
require_once "../includes/footer.php";

View File

@@ -46,7 +46,7 @@ if (isset($_GET['certificate_fetch_parse_json_details'])) {
if (isset($_GET['merge_ticket_get_json_details'])) {
enforceUserPermission('module_support');
$merge_into_ticket_number = intval($_GET['merge_into_ticket_number']);
$merge_into_ticket_number = intval(preg_replace('/[^0-9]/', '', $_GET['merge_into_ticket_number']));
$sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_number, ticket_prefix, ticket_subject, ticket_priority, ticket_status, ticket_status_name, client_name, contact_name FROM tickets
LEFT JOIN clients ON ticket_client_id = client_id
@@ -432,7 +432,7 @@ if (isset($_GET['get_totp_token_via_id'])) {
}
if (isset($_GET['get_readable_pass'])) {
echo json_encode(GenerateReadablePassword(4));
echo json_encode(GenerateReadablePassword(1));
}
/*
@@ -675,3 +675,320 @@ if (isset($_POST['update_recurring_invoice_items_order'])) {
echo json_encode(['status' => 'success']);
exit;
}
if (isset($_GET['client_duplicate_check'])) {
enforceUserPermission('module_client', 2);
$name = sanitizeInput($_GET['name']);
$response['message'] = ""; // default
if (strlen($name) >= 5) {
$sql_clients = mysqli_query($mysqli, "SELECT client_name FROM clients
WHERE client_archived_at IS NULL
AND client_name LIKE '%$name%'
ORDER BY client_id DESC LIMIT 1"
);
if (mysqli_num_rows($sql_clients) > 0) {
while ($row = mysqli_fetch_array($sql_clients)) {
$response['message'] = "<i class='fas fa-fw fa-copy mr-2'></i> Potential duplicate: <i>" . nullable_htmlentities($row['client_name']) . "</i> already exists.";
}
}
}
echo json_encode($response);
}
if (isset($_GET['contact_email_check'])) {
enforceUserPermission('module_client', 2);
$email = sanitizeInput($_GET['email']);
$domain = sanitizeInput(substr($_GET['email'], strpos($_GET['email'], '@') + 1));
$response['message'] = ""; // default
if (strlen($email) >= 3) {
// 1. Duplicate check
$sql_contacts = mysqli_query($mysqli, "SELECT contact_email FROM contacts WHERE contact_email = '$email' LIMIT 1");
if (mysqli_num_rows($sql_contacts) > 0) {
while ($row = mysqli_fetch_array($sql_contacts)) {
$response['message'] = "<i class='fas fa-fw fa-copy mr-2'></i> Potential duplicate: <i>" . nullable_htmlentities($row['contact_email']) . "</i> already exists.";
}
}
// 2. MX record check
if (!checkdnsrr($domain, 'MX')) {
$response['message'] = "<i class='fas fa-fw fa-exclamation-triangle mr-2'></i> E-mail domain invalid.";
}
}
echo json_encode($response);
}
if (isset($_GET['ai_reword'])) {
header('Content-Type: application/json');
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
$row = mysqli_fetch_array($sql);
$model_name = $row['ai_model_name'];
$promptText = $row['ai_model_prompt'];
$url = $row['ai_provider_api_url'];
$key = $row['ai_provider_api_key'];
// Collecting the input data from the AJAX request.
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); // Convert JSON into array.
$userText = $input['text'];
// Preparing the data for the OpenAI Chat API request.
$data = [
"model" => "$model_name", // Specify the model
"messages" => [
["role" => "system", "content" => $promptText],
["role" => "user", "content" => $userText],
],
"temperature" => 0.5
];
// Initialize cURL session to the OpenAI Chat API.
$ch = curl_init("$url");
// Set cURL options for the request.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $key,
]);
// Execute the cURL session and capture the response.
$response = curl_exec($ch);
curl_close($ch);
// Decode the JSON response.
$responseData = json_decode($response, true);
// Check if the response contains the expected data and return it.
if (isset($responseData['choices'][0]['message']['content'])) {
// Get the response content.
$content = $responseData['choices'][0]['message']['content'];
// Clean any leading "html" word or other unwanted text at the beginning.
$content = preg_replace('/^html/i', '', $content); // Remove any occurrence of 'html' at the start
// Clean the response content to remove backticks or code block markers.
$cleanedContent = str_replace('```', '', $content); // Remove backticks if they exist.
// Trim any leading/trailing whitespace.
$cleanedContent = trim($cleanedContent);
// Return the cleaned response.
echo json_encode(['rewordedText' => $cleanedContent]);
} else {
// Handle errors or unexpected response structure.
echo json_encode(['rewordedText' => 'Failed to get a response from the AI API.']);
}
}
if (isset($_GET['ai_create_document_template'])) {
// get_ai_document_template.php
header('Content-Type: text/html; charset=UTF-8');
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
$row = mysqli_fetch_array($sql);
$model_name = $row['ai_model_name'];
$url = $row['ai_provider_api_url'];
$key = $row['ai_provider_api_key'];
$prompt = $_POST['prompt'] ?? '';
// Basic validation
if(empty($prompt)){
echo "No prompt provided.";
exit;
}
// Prepare prompt
$system_message = "You are a helpful IT documentation assistant. You will create a well-structured HTML template for IT documentation based on a given prompt. Include headings, subheadings, bullet points, and possibly tables for clarity. No Lorem Ipsum, use realistic placeholders and professional language.";
$user_message = "Create an HTML formatted IT documentation template based on the following request:\n\n\"$prompt\"\n\nThe template should be structured, professional, and useful for IT staff. Include relevant sections, instructions, prerequisites, and best practices.";
$post_data = [
"model" => "$model_name",
"messages" => [
["role" => "system", "content" => $system_message],
["role" => "user", "content" => $user_message]
],
"temperature" => 0.5
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $key
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo "Error: " . curl_error($ch);
exit;
}
curl_close($ch);
$response_data = json_decode($response, true);
$template = $response_data['choices'][0]['message']['content'] ?? "<p>No content returned from AI.</p>";
// Print the generated HTML template directly
echo $template;
}
if (isset($_GET['ai_ticket_summary'])) {
header('Content-Type: text/html; charset=UTF-8');
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
$row = mysqli_fetch_array($sql);
$model_name = $row['ai_model_name'];
$url = $row['ai_provider_api_url'];
$key = $row['ai_provider_api_key'];
// Retrieve the ticket_id from POST
$ticket_id = intval($_POST['ticket_id']);
// Query the database for ticket details
$sql = mysqli_query($mysqli, "
SELECT ticket_subject, ticket_details, ticket_source, ticket_priority, ticket_status_name, category_name
FROM tickets
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
LEFT JOIN categories ON ticket_category = category_id
WHERE ticket_id = $ticket_id
LIMIT 1
");
$row = mysqli_fetch_assoc($sql);
$ticket_subject = $row['ticket_subject'];
$ticket_details = strip_tags($row['ticket_details']); // strip HTML for cleaner prompt
$ticket_status = $row['ticket_status_name'];
$ticket_category = $row['category_name'];
$ticket_source = $row['ticket_source'];
$ticket_priority = $row['ticket_priority'];
// Get ticket replies
$sql_replies = mysqli_query($mysqli, "
SELECT ticket_reply, ticket_reply_type, user_name
FROM ticket_replies
LEFT JOIN users ON ticket_reply_by = user_id
WHERE ticket_reply_ticket_id = $ticket_id
AND ticket_reply_archived_at IS NULL
ORDER BY ticket_reply_id ASC
");
$all_replies_text = "";
while ($reply = mysqli_fetch_assoc($sql_replies)) {
$reply_type = $reply['ticket_reply_type'];
$reply_text = strip_tags($reply['ticket_reply']);
$reply_by = $reply['user_name'];
$all_replies_text .= "\nReply Type: $reply_type Reply By: $reply_by: Reply Text: $reply_text";
}
$prompt = "
Summarize the following IT support ticket and its responses in a concise, clear, and professional manner.
The summary should include:
1. Main Issue: What was the problem reported by the user?
2. Actions Taken: What steps were taken to address the issue?
3. Resolution or Next Steps: Was the issue resolved or is it ongoing?
Please ensure:
- If there are multiple issues, summarize each separately.
- Urgency: If the ticket or replies express urgency or escalation, highlight it.
- Attachments: If mentioned in the ticket, note any relevant attachments or files.
- Avoid extra explanations or unnecessary information.
Ticket Data:
- Ticket Source: $ticket_source
- Current Ticket Status: $ticket_status
- Ticket Priority: $ticket_priority
- Ticket Category: $ticket_category
- Ticket Subject: $ticket_subject
- Ticket Details: $ticket_details
- Replies:
$all_replies_text
Formatting instructions:
- Use valid HTML tags only.
- Use <h3> for section headers (Main Issue, Actions Taken, Resolution).
- Use <ul><li> for bullet points under each section.
- Do NOT wrap the output in ```html or any other code fences.
- Do NOT include <html>, <head>, or <body>.
- Output only the summary content in pure HTML.
If any part of the ticket or replies is unclear or ambiguous, mention it in the summary and suggest if further clarification is needed.
";
// Prepare the POST data
$post_data = [
"model" => "$model_name",
"messages" => [
["role" => "system", "content" => "Your task is to summarize IT support tickets with clear, concise details."],
["role" => "user", "content" => $prompt]
],
"temperature" => 0.3
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $key
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo "Error: " . curl_error($ch);
exit;
}
curl_close($ch);
$response_data = json_decode($response, true);
$summary = $response_data['choices'][0]['message']['content'] ?? "No summary available.";
echo $summary; // nl2br to convert newlines to <br>, htmlspecialchars to prevent XSS
}
// Stops people trying to use sub-domains in the domains tracker
if (isset($_GET['apex_domain_check'])) {
enforceUserPermission('module_support', 2);
$domain = sanitizeInput($_GET['domain']);
$response['message'] = ""; // default
if (strlen($domain) >= 4) {
// SOA record check
// This isn't 100%, as sub-domains can have their own SOA but will capture 99%
if (!checkdnsrr($domain, 'SOA')) {
$response['message'] = "<i class='fas fa-fw fa-exclamation-triangle mr-2'></i> Domain name is invalid.";
}
}
echo json_encode($response);
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,17 +37,23 @@ enforceUserPermission('module_support');
//Asset Type from GET
if (isset($_GET['type']) && ($_GET['type']) == 'workstation') {
$type_query = "asset_type = 'desktop' OR asset_type = 'laptop'";
$type_filter = "workstation";
} elseif (isset($_GET['type']) && ($_GET['type']) == 'server') {
$type_query = "asset_type = 'server'";
$type_filter = "server";
} elseif (isset($_GET['type']) && ($_GET['type']) == 'virtual') {
$type_query = "asset_type = 'Virtual Machine'";
$type_filter = "virtual";
} elseif (isset($_GET['type']) && ($_GET['type']) == 'network') {
$type_query = "asset_type = 'Firewall/Router' OR asset_type = 'Switch' OR asset_type = 'Access Point'";
$type_filter = "network";
} elseif (isset($_GET['type']) && ($_GET['type']) == 'other') {
$type_query = "asset_type NOT LIKE 'laptop' AND asset_type NOT LIKE 'desktop' AND asset_type NOT LIKE 'server' AND asset_type NOT LIKE 'virtual machine' AND asset_type NOT LIKE 'firewall/router' AND asset_type NOT LIKE 'switch' AND asset_type NOT LIKE 'access point'";
$type_filter = "other";
} else {
$type_query = "asset_type LIKE '%'";
$_GET['type'] = '';
$type_filter = '';
}
if (!$client_url) {
@@ -72,9 +78,21 @@ if ($client_url && isset($_GET['location']) && !empty($_GET['location'])) {
$location_filter = 0;
}
// Tags Filter
if (isset($_GET['tags']) && is_array($_GET['tags']) && !empty($_GET['tags'])) {
// Sanitize each element of the tags array
$sanitizedTags = array_map('intval', $_GET['tags']);
// Convert the sanitized tags into a comma-separated string
$tag_filter = implode(",", $sanitizedTags);
$tag_query = "AND tag_id IN ($tag_filter)";
} else {
$tag_filter = 0;
$tag_query = '';
}
//Get Asset Counts
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "
SELECT
SELECT
COUNT(*) AS all_count,
SUM(CASE WHEN asset_type IN ('laptop', 'desktop') THEN 1 ELSE 0 END) AS workstation_count,
SUM(CASE WHEN asset_type = 'server' THEN 1 ELSE 0 END) AS server_count,
@@ -84,12 +102,16 @@ $row = mysqli_fetch_assoc(mysqli_query($mysqli, "
FROM (
SELECT assets.* FROM assets
LEFT JOIN clients ON client_id = asset_client_id
LEFT JOIN contacts ON asset_contact_id = contact_id
LEFT JOIN locations ON asset_location_id = location_id
LEFT JOIN contacts ON asset_contact_id = contact_id
LEFT JOIN locations ON asset_location_id = location_id
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE $archive_query
$tag_query
$access_permission_query
$client_query
GROUP BY asset_id
) AS filtered_assets;
"));
@@ -111,41 +133,28 @@ $network_count = intval($row['network_count']);
//Other Count
$other_count = intval($row['other_count']);
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM assets
LEFT JOIN clients ON asset_client_id = client_id
LEFT JOIN contacts ON asset_contact_id = contact_id
LEFT JOIN locations ON asset_location_id = location_id
LEFT JOIN contacts ON asset_contact_id = contact_id
LEFT JOIN locations ON asset_location_id = location_id
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE $archive_query
AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%')
$tag_query
AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%' OR tag_name LIKE '%$q%')
AND ($type_query)
$access_permission_query
$location_query
$client_query
GROUP BY asset_id
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
// OS typeahead suggestions
$os_sql = mysqli_query($mysqli, "SELECT DISTINCT asset_os AS label FROM assets WHERE asset_archived_at IS NULL");
if ($os_sql && mysqli_num_rows($os_sql) > 0) {
$os_arr = [];
while ($row = mysqli_fetch_assoc($os_sql)) {
// jQuery UI Autocomplete expects {label: "...", value: "..."}
$label = $row['label'];
$os_arr[] = ['label' => $label, 'value' => $label];
}
$json_os = json_encode($os_arr);
}
?>
<div class="col-sm-12 mb-3">
@@ -185,20 +194,22 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
<div class="card-tools">
<?php if (lookupUserPermission("module_support") >= 2) { ?>
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addAssetModal">
<i class="fas fa-plus mr-2"></i>New <?php if (!empty($_GET['type'])) { echo ucwords(strip_tags(nullable_htmlentities($_GET['type']))); } else { echo "Asset"; } ?>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/asset/asset_add.php?<?= $client_url ?>&type=<?= $type_filter ?>">
<i class="fas fa-plus mr-2"></i>New <?php if ($type_filter) { echo ucwords($type_filter); } else { echo "Asset"; } ?>
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<?php if ($client_url) { ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importAssetModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/asset/asset_import.php?<?= $client_url ?>">
<i class="fa fa-fw fa-upload mr-2"></i>Import
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<?php if ($num_rows[0] > 0) { ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportAssetModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/asset/asset_export.php?<?= $client_url ?>">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
<?php } ?>
@@ -233,7 +244,7 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
$sql_locations_filter = mysqli_query($mysqli, "
SELECT DISTINCT location_id, location_name
FROM locations
WHERE location_client_id = $client_id
WHERE location_client_id = $client_id
AND ( EXISTS (SELECT 1 FROM assets WHERE asset_location_id = location_id AND $archive_query) OR location_id = $location_filter)
ORDER BY location_name ASC
");
@@ -257,7 +268,7 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
<?php
$sql_clients_filter = mysqli_query($mysqli, "
SELECT DISTINCT client_id, client_name
SELECT DISTINCT client_id, client_name
FROM clients
JOIN assets ON asset_client_id = client_id
WHERE $archive_query
@@ -277,7 +288,32 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
</div>
</div>
<?php } ?>
<div class="col-md-3">
<div class="col-md-2">
<div class="input-group mb-3 mb-md-0">
<select onchange="this.form.submit()" class="form-control select2" name="tags[]" data-placeholder="- Select Tags -" multiple>
<?php
$sql_tags_filter = mysqli_query($mysqli, "
SELECT tag_id, tag_name
FROM tags
LEFT JOIN asset_tags ON asset_tag_tag_id = tag_id
LEFT JOIN assets ON asset_tag_asset_id = asset_id
WHERE tag_type = 5
$client_query OR tag_id IN ($tag_filter)
GROUP BY tag_id
HAVING COUNT(asset_tag_asset_id) > 0 OR tag_id IN ($tag_filter)
");
while ($row = mysqli_fetch_array($sql_tags_filter)) {
$tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']); ?>
<option value="<?php echo $tag_id ?>" <?php if (isset($_GET['tags']) && in_array($tag_id, $_GET['tags'])) { echo 'selected'; } ?>> <?php echo $tag_name ?> </option>
<?php } ?>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<select onchange="this.form.submit()" class="form-control select2" name="show_column[]" data-placeholder="- Show Additional Columns -" multiple>
<option
@@ -298,7 +334,7 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
</select>
</div>
</div>
<div class="col-md-3">
<div class="col-md-2">
<div class="btn-group float-right">
<a href="?<?php echo $client_url; ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
@@ -310,27 +346,47 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
</button>
<div class="dropdown-menu">
<?php if ($client_url) { ?>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignContactModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_contact.php?<?= $client_url ?>"
data-bulk="true">
<i class="fas fa-fw fa-user mr-2"></i>Assign Contact
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignLocationModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_location.php?<?= $client_url ?>"
data-bulk="true">
<i class="fas fa-fw fa-map-marker-alt mr-2"></i>Assign Location
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignPhysicalLocationModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_tags.php"
data-bulk="true">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_physical_location.php"
data-bulk="true">
<i class="fas fa-fw fa-map-marker-alt mr-2"></i>Set Physical Location
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditStatusModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_edit_status.php"
data-bulk="true">
<i class="fas fa-fw fa-info mr-2"></i>Set Status
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAddTicketModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_add_ticket.php"
data-modal-size="lg"
data-bulk="true">
<i class="fas fa-fw fa-life-ring mr-2"></i>Create Tickets
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkTransferAssetClientModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_transfer_client.php?<?= $client_url ?>"
data-bulk="true">
<i class="fas fa-fw fa-arrow-right mr-2"></i>Transfer to Client
</a>
<?php if ($archived) { ?>
@@ -409,7 +465,7 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
IP <?php if ($sort == 'interface_ip') { echo $order_icon; } ?>
</a>
</th>
<?php if (isset($_GET['show_column']) && is_array($_GET['show_column']) && in_array('Mac_Address', $_GET['show_column'])) { ?>
<?php if (isset($_GET['show_column']) && is_array($_GET['show_column']) && in_array('Mac_Address', $_GET['show_column'])) { ?>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=interface_mac&order=<?php echo $disp; ?>">
MAC Address <?php if ($sort == 'interface_mac') { echo $order_icon; } ?>
@@ -551,7 +607,7 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
}
$contact_name = nullable_htmlentities($row['contact_name']);
if ($contact_name) {
$contact_name_display = "<a class='ajax-modal' href='#' data-modal-url='modals/contact/contact_details.php?id=$asset_contact_id' data-modal-size='lg'>$contact_name $contact_archive_display</a>";
$contact_name_display = "<a class='ajax-modal' href='#' data-modal-url='modals/contact/contact_details.php?id=$asset_contact_id' data-modal-size='lg'>$contact_name $contact_archive_display</a>";
} else {
$contact_name_display = "-";
}
@@ -570,20 +626,48 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
$sql_credentials = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_asset_id = $asset_id");
$credential_count = mysqli_num_rows($sql_credentials);
// Tags
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='assets.php?$client_url tags[]=$asset_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
?>
<tr>
<td class="pr-0 bg-light">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="asset_ids[]" value="<?php echo $asset_id ?>">
<input class="form-check-input bulk-select" type="checkbox" name="asset_ids[]" value="<?= $asset_id ?>">
</div>
</td>
<td>
<a class="text-dark" href="asset_details.php?client_id=<?php echo $client_id; ?>&asset_id=<?php echo $asset_id; ?>">
<a class="text-dark" href="asset_details.php?client_id=<?= $client_id ?>&asset_id=<?= $asset_id ?>">
<div class="media">
<i class="fa fa-fw fa-2x fa-<?php echo $device_icon; ?> mr-3 mt-1"></i>
<i class="fa fa-fw fa-2x fa-<?= $device_icon ?> mr-3 mt-1"></i>
<div class="media-body">
<div><?php echo $asset_name; ?></div>
<div><small class="text-secondary"><?php echo $asset_description; ?></small></div>
<div><?= $asset_name ?></div>
<div><small class="text-secondary"><?= $asset_description ?></small></div>
<?php
if ($asset_tags_display) { ?>
<div class="mt-1">
<?= $asset_tags_display ?>
</div>
<?php } ?>
</div>
</div>
</a>
@@ -699,16 +783,6 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
</tbody>
</table>
</div>
<?php
if ($client_url) {
require_once "modals/asset/asset_bulk_assign_contact.php";
require_once "modals/asset/asset_bulk_assign_location.php";
}
?>
<?php require_once "modals/asset/asset_bulk_assign_physical_location.php"; ?>
<?php require_once "modals/asset/asset_bulk_transfer_client.php"; ?>
<?php require_once "modals/asset/asset_bulk_edit_status.php"; ?>
<?php require_once "modals/asset/asset_bulk_add_ticket.php"; ?>
</form>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
@@ -716,26 +790,5 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
<script src="../js/bulk_actions.js"></script>
<!-- JSON Autocomplete / type ahead -->
<link rel="stylesheet" href="../plugins/jquery-ui/jquery-ui.min.css">
<script src="../plugins/jquery-ui/jquery-ui.min.js"></script>
<script>
$(function() {
var operatingSystems = <?php echo $json_os; ?>;
$("#os").autocomplete({
source: operatingSystems, // Should be an array of objects with 'label' and 'value'
select: function(event, ui) {
$("#os").val(ui.item.label); // Set the input field value to the selected label
return false;
}
});
});
</script>
<?php
require_once "modals/asset/asset_add.php";
require_once "modals/asset/asset_export.php";
if ($client_url) {
require_once "modals/asset/asset_import.php";
}
require_once "../includes/footer.php";

View File

@@ -1,113 +0,0 @@
<?php
require_once "includes/inc_all.php";
// Perms
enforceUserPermission('module_financial');
// Fetch categories
$query = "SELECT category_id, category_name FROM categories WHERE category_type ='Expense' AND category_archived_at IS NULL";
$result = mysqli_query($mysqli, $query);
$categories = [];
while($row = mysqli_fetch_assoc($result)) {
$categories[] = $row;
}
// Fetch years with budget
$query = "SELECT DISTINCT budget_year FROM budget ORDER BY budget_year ASC";
$result = mysqli_query($mysqli, $query);
$years = [];
while ($row = mysqli_fetch_assoc($result)) {
$years[] = $row['budget_year'];
}
// Fetch current year budgets
$currentYear = date("Y");
if (isset($_GET['year'])) {
$currentYear = intval($_GET['year']);
}
$query = "SELECT * FROM budget WHERE budget_year = $currentYear";
$result = mysqli_query($mysqli, $query);
$budgets = [];
while ($row = mysqli_fetch_assoc($result)) {
$budgets[] = $row;
}
$months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
$columnTotals = array_fill(0, 12, 0);
$grandTotal = 0;
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Budget for <span id="currentYear"><?php echo $currentYear; ?></span></h3>
<div class="card-tools">
<a href="budget_edit.php" class="btn btn-primary">
<i class="fas fa-edit mr-2"></i>Edit Budget
</a>
</div>
</div>
<div class="card-body">
<form id="yearForm" method="GET" action="budget.php">
<div class="form-group">
<select class="form-control" name="year" id="yearSelect" onchange="submit();">
<?php foreach ($years as $year): ?>
<option value="<?php echo $year; ?>" <?php if ($year == $currentYear) { echo 'selected'; } ?>><?php echo $year; ?></option>
<?php endforeach; ?>
</select>
</div>
</form>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Expense</th>
<?php foreach ($months as $month): ?>
<th><?php echo $month; ?></th>
<?php endforeach; ?>
<th>Total</th>
</tr>
</thead>
<tbody>
<?php foreach ($categories as $category): ?>
<tr>
<td><?php echo nullable_htmlentities($category['category_name']); ?></td>
<?php
$rowTotal = 0;
foreach ($months as $index => $month):
$amount = getBudgetAmount($budgets, $category['category_id'], $index + 1);
$rowTotal += $amount;
$columnTotals[$index] += $amount;
?>
<td><?php echo $amount; ?></td>
<?php endforeach; ?>
<td><?php echo $rowTotal; ?></td>
</tr>
<?php
$grandTotal += $rowTotal;
endforeach; ?>
</tbody>
<tfoot>
<tr>
<th>Total</th>
<?php foreach ($columnTotals as $total): ?>
<th><?php echo $total; ?></th>
<?php endforeach; ?>
<th><?php echo $grandTotal; ?></th>
</tr>
</tfoot>
</table>
</div>
<?php
function getBudgetAmount($budgets, $categoryId, $month) {
foreach ($budgets as $budget) {
if ($budget['budget_category_id'] == $categoryId && $budget['budget_month'] == $month) {
return intval($budget['budget_amount']);
}
}
return 0;
}
require_once "../includes/footer.php";
?>

View File

@@ -1,114 +0,0 @@
<?php
require_once "includes/inc_all.php";
enforceUserPermission('module_financial', 2);
// Fetch categories
$query = "SELECT category_id, category_name FROM categories WHERE category_type ='Expense' AND category_archived_at IS NULL";
$result = mysqli_query($mysqli, $query);
$categories = [];
while($row = mysqli_fetch_assoc($result)) {
$categories[] = $row;
}
// Fetch current year budgets
$currentYear = date("Y");
if(isset($_GET['year'])) {
$currentYear = intval($_GET['year']);
}
$query = "SELECT * FROM budget WHERE budget_year = $currentYear";
$result = mysqli_query($mysqli, $query);
$budgets = [];
while($row = mysqli_fetch_assoc($result)) {
$budgets[] = $row;
}
$months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
$columnTotals = array_fill(0, 12, 0);
$grandTotal = 0;
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Editing Budget for <span id="currentYear"><?php echo $currentYear; ?></span></h3>
<div class="card-tools">
<a href="budget.php" class="btn btn-default text-dark">
<i class="fas fa-eye mr-2"></i>View Budget
</a>
<button type="submit" name="save_budget" form="budgetForm" class="btn btn-primary"><i class="fas fa-fw fa-check mr-2"></i>Save Budget</button>
<button type="submit" name="delete_budget" form="budgetForm" class="btn btn-danger"><i class="fas fa-fw fa-trash mr-2"></i>Delete Budget</button>
</div>
</div>
<div class="card-body">
<form id="yearForm" method="GET" action="budget.php">
<div class="form-group">
<select class="form-control" name="year" id="yearSelect" onchange="submit();">
<?php for ($i = $currentYear - 10; $i <= $currentYear + 5; $i++): ?>
<option value="<?php echo $i; ?>" <?php if ($i == $currentYear) echo 'selected'; ?>><?php echo $i; ?></option>
<?php endfor; ?>
</select>
</div>
</form>
<form id="budgetForm" method="POST" action="post.php">
<input type="hidden" name="year" value="<?php echo $currentYear; ?>">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Expense</th>
<?php foreach ($months as $month): ?>
<th><?php echo $month; ?></th>
<?php endforeach; ?>
<th>Total</th>
</tr>
</thead>
<tbody>
<?php foreach ($categories as $category): ?>
<tr>
<td><?php echo nullable_htmlentities($category['category_name']); ?></td>
<?php
$rowTotal = 0;
foreach ($months as $index => $month):
$amount = getBudgetAmount($budgets, $category['category_id'], $index + 1);
$rowTotal += $amount;
$columnTotals[$index] += $amount;
?>
<td><input type='text' inputmode='numeric' pattern='[0-9]*' class="form-control" name="budget[<?php echo intval($category['category_id']); ?>][<?php echo $index + 1; ?>]" value="<?php echo $amount; ?>"></td>
<?php endforeach; ?>
<td><?php echo $rowTotal; ?></td>
</tr>
<?php
$grandTotal += $rowTotal;
endforeach; ?>
</tbody>
<tfoot>
<tr>
<th>Total</th>
<?php foreach ($columnTotals as $total): ?>
<th><?php echo $total; ?></th>
<?php endforeach; ?>
<th><?php echo $grandTotal; ?></th>
</tr>
</tfoot>
</table>
</form>
</div>
</div>
<?php
function getBudgetAmount($budgets, $categoryId, $month) {
foreach ($budgets as $budget) {
if ($budget['budget_category_id'] == $categoryId && $budget['budget_month'] == $month) {
return intval($budget['budget_amount']);
}
}
return 0;
}
require_once "../includes/footer.php";
?>

View File

@@ -33,7 +33,7 @@ if (isset($_GET['calendar_id'])) {
<div class="card-header py-2">
<h3 class="card-title mt-1">Calendars</h3>
<div class="card-tools">
<button type="button" class="btn btn-dark btn-sm" data-toggle="modal" data-target="#addCalendarModal"><i class="fas fa-plus"></i></button>
<button type="button" class="btn btn-dark btn-sm ajax-modal" data-modal-url="modals/calendar/calendar_add.php"><i class="fas fa-plus"></i></button>
</div>
</div>
<div class="card-body">
@@ -82,8 +82,6 @@ if (isset($_GET['calendar_id'])) {
<?php
require_once "modals/calendar/calendar_event_add.php";
require_once "modals/calendar/calendar_add.php";
//loop through IDs and create a modal for each
$sql = mysqli_query($mysqli, "SELECT * FROM calendar_events LEFT JOIN calendars ON event_calendar_id = calendar_id $client_event_query");

View File

@@ -64,11 +64,12 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<h3 class="card-title mt-2"><i class="fas fa-fw fa-lock mr-2"></i>Certificates</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addCertificateModal"><i class="fas fa-plus mr-2"></i>New Certificate</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/certificate/certificate_add.php?<?= $client_url ?>"><i class="fas fa-plus mr-2"></i>New Certificate</button>
<?php if ($num_rows[0] > 0) { ?>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportCertificateModal">
<a class="dropdown-item text-dark ajax-modal" href="#"\
data-modal-url="modals/certificate/certificate_export.php?<?= $client_url ?>">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
</div>
@@ -78,7 +79,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<div class="card-body">
<form autocomplete="off">
<?php if ($client_url) { ?>
<?php if ($client_url) { ?>
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<?php } ?>
<input type="hidden" name="archived" value="<?php echo $archived; ?>">
@@ -103,7 +104,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php
$sql_clients_filter = mysqli_query($mysqli, "
SELECT DISTINCT client_id, client_name
SELECT DISTINCT client_id, client_name
FROM clients
JOIN certificates ON certificate_client_id = client_id
WHERE $archive_query
@@ -126,7 +127,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="col-md-6">
<div class="btn-group float-right">
<a href="?<?php echo $client_url; ?>archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
<a href="?<?php echo $client_url; ?>archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived
</a>
@@ -249,8 +250,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<td><?php echo $certificate_issued_by; ?></td>
<td>
<div><?php echo $certificate_expire; ?></div>
<div><small><?php echo $certificate_expire_ago; ?></small></div>
<div><?php echo $certificate_expire ?: '-'; ?></div>
<?php if (!empty($certificate_expire)) { ?>
<div><small><?php echo $certificate_expire_ago; ?></small></div>
<?php } ?>
</td>
<?php if (!$client_url) { ?>
<td><a href="certificates.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
@@ -281,7 +284,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php } ?>
<?php } ?>
</div>
</div>
@@ -297,17 +300,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</form>
</div>
<?php require_once "../includes/filter_footer.php";
?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<?php
require_once "modals/certificate/certificate_add.php";
require_once "modals/certificate/certificate_export.php";
?>
<script src="../js/bulk_actions.js"></script>
<script src="js/certificate_fetch_ssl.js"></script>
<?php require_once "../includes/footer.php";
<?php require_once "../includes/footer.php";

View File

@@ -86,17 +86,19 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-tools">
<?php if (lookupUserPermission("module_client") >= 2) { ?>
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addClientModal">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/client/client_add.php<?php if ($leads_filter) { echo "?lead=1"; } ?>">
<i class="fas fa-plus mr-2"></i>New
<?php if ($leads_filter == 0) { echo "Client"; } else { echo "Lead"; } ?>
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importClientModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/client/client_import.php">
<i class="fa fa-fw fa-upload mr-2"></i>Import
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportClientModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/client/client_export.php">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
</div>
@@ -128,7 +130,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<div class="btn-group">
<a href="?<?php echo $url_query_strings_sort ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
<a href="?<?php echo $url_query_strings_sort ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if ($archived == 1) { echo "primary"; } else { echo "default"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived
</a>
@@ -137,23 +139,41 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-fw fa-layer-group"></i><span class="d-none d-sm-inline ml-2">Action</span> (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditHourlyRateModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/client/client_bulk_add_ticket.php"
data-modal-size="lg"
data-bulk="true">
<i class="fas fa-fw fa-life-ring mr-2"></i>Open Tickets
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/client/client_bulk_edit_hourly_rate.php"
data-bulk="true">
<i class="fas fa-fw fa-clock mr-2"></i>Set Hourly Rate
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditIndustryModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/client/client_bulk_edit_industry.php"
data-bulk="true">
<i class="fas fa-fw fa-briefcase mr-2"></i>Set Industry
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditReferralModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/client/client_bulk_edit_referral.php"
data-bulk="true">
<i class="fas fa-fw fa-link mr-2"></i>Set Referral
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignTagsModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/client/client_bulk_assign_tags.php"
data-bulk="true">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkSendEmailModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/client/client_bulk_email.php"
data-modal-size="lg"
data-bulk="true">
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Email
</a>
<?php if ($archived) { ?>
@@ -175,59 +195,37 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
</div>
</div>
<div
class="collapse
<?php
if (
isset($_GET['dtf'])
|| $industry_filter
|| $referral_filter
|| (isset($_GET['tags']) && is_array($_GET['tags']))
|| $_GET['canned_date'] !== "custom" )
{
echo "show";
}
<div
class="collapse
<?php
if (isset($_GET['dtf']) && $_GET['dtf'] !== '1970-01-01'
|| $industry_filter
|| $referral_filter
|| (isset($_GET['tags']) && is_array($_GET['tags']))
)
{ echo "show"; }
?>
"
id="advancedFilter"
>
<div class="row">
<div class="col-md-2">
<div class="col-md-3">
<div class="form-group">
<label>Canned date</label>
<select onchange="this.form.submit()" class="form-control select2" name="canned_date">
<option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="custom">Custom</option>
<option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option>
<option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option>
<option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option>
<option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option>
<option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option>
<option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option>
<option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option>
<option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option>
</select>
<label>Date range</label>
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
<input type="hidden" name="canned_date" id="canned_date" value="<?php echo nullable_htmlentities($_GET['canned_date']) ?? ''; ?>">
<input type="hidden" name="dtf" id="dtf" value="<?php echo nullable_htmlentities($dtf ?? ''); ?>">
<input type="hidden" name="dtt" id="dtt" value="<?php echo nullable_htmlentities($dtt ?? ''); ?>">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date from</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date to</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>">
</div>
</div>
<div class="col-md-2">
<div class="col-md-3">
<div class="form-group">
<label>Tag</label>
<select onchange="this.form.submit()" class="form-control select2" name="tags[]" data-placeholder="- Select Tags -" multiple>
<?php
<?php
$sql_tags_filter = mysqli_query($mysqli, "
SELECT tags.tag_id, tags.tag_name
FROM tags
FROM tags
LEFT JOIN client_tags ON client_tags.tag_id = tags.tag_id
WHERE tag_type = 1
GROUP BY tags.tag_id
@@ -285,8 +283,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
</form>
</div>
<form id="bulkActions" action="post.php" method="post" enctype="multipart/form-data">
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="table-responsive-sm">
<table class="table table-hover mb-0 text-nowrap">
@@ -368,11 +366,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
}
// Counts
// Contact Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('contact_id') AS num FROM contacts WHERE contact_client_id = $client_id AND contact_archived_at IS NULL"));
$contact_count = $row['num'];
if ($contact_count) {
if ($contact_count) {
$contact_count_display = "<a href='contacts.php?client_id=$client_id' class='mr-2 mb-1 badge badge-pill badge-dark p-2' title='Contacts ($contact_count)'><i class='fas fa-fw fa-users mr-2'></i>$contact_count</a>";
} else {
$contact_count_display = '';
@@ -381,34 +379,34 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
// Vendors Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('vendor_id') AS num FROM vendors WHERE vendor_client_id = $client_id AND vendor_archived_at IS NULL"));
$vendor_count = $row['num'];
if ($vendor_count) {
if ($vendor_count) {
$vendor_count_display = "<a href='vendors.php?client_id=$client_id' class='mr-2 mb-1 badge badge-pill badge-dark p-2' title='Vendors ($vendor_count)'><i class='fas fa-fw fa-building mr-2'></i>$vendor_count</a>";
} else {
$vendor_count_display = '';
}
// Asset Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('asset_id') AS num FROM assets WHERE asset_client_id = $client_id AND asset_archived_at IS NULL"));
$asset_count = $row['num'];
if ($asset_count) {
if ($asset_count) {
$asset_count_display = "<a href='assets.php?client_id=$client_id' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Assets ($asset_count)'><i class='fas fa-fw fa-desktop mr-2'></i>$asset_count</a>";
} else {
$asset_count_display = '';
}
// Credential Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('credential_id') AS num FROM credentials WHERE credential_client_id = $client_id AND credential_archived_at IS NULL"));
$credential_count = $row['num'];
if ($credential_count) {
if ($credential_count) {
$credential_count_display = "<a href='credentials.php?client_id=$client_id' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Credentials ($credential_count)'><i class='fas fa-fw fa-key mr-2'></i>$credential_count</a>";
} else {
$credential_count_display = '';
}
// Software Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('software_id') AS num FROM software WHERE software_client_id = $client_id AND software_archived_at IS NULL"));
$software_count = $row['num'];
if ($software_count) {
if ($software_count) {
$software_count_display = "<a href='software.php?client_id=$client_id' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Licenses ($software_count)'><i class='fas fa-fw fa-cube mr-2'></i>$software_count</a>";
} else {
$software_count_display = '';
@@ -417,7 +415,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
// Ticket Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets WHERE ticket_client_id = $client_id AND ticket_archived_at IS NULL"));
$ticket_count = $row['num'];
if ($ticket_count) {
if ($ticket_count) {
$ticket_count_display = "<a href='tickets.php?client_id=$client_id' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Tickets ($ticket_count)'><i class='fas fa-fw fa-life-ring mr-2'></i>$ticket_count</a>";
} else {
$ticket_count_display = '';
@@ -522,10 +520,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
}
if (!empty($contact_name)) { ?>
<div class="text-bold">
<div class="text-bold">
<i class="fa fa-fw fa-user text-secondary mr-2 mb-2"></i><a class="ajax-modal" href="#"
data-modal-url="modals/contact/contact_details.php?client_id=<?= $client_id ?>&id=<?= $contact_id ?>" data-modal-size="lg"><?= $contact_name; ?>
</a>
</div>
<?php } else {
@@ -618,23 +616,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody>
</table>
</div>
<?php
require_once "modals/client/client_bulk_edit_industry.php";
require_once "modals/client/client_bulk_edit_referral.php";
require_once "modals/client/client_bulk_edit_hourly_rate.php";
require_once "modals/client/client_bulk_assign_tags.php";
require_once "modals/client/client_bulk_email.php";
?>
</form>
<!-- Ends Card Body -->
<?php require_once "../includes/filter_footer.php"; ?>
</div> <!-- End Card -->
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/client/client_add.php";
require_once "modals/client/client_import.php";
require_once "modals/client/client_export.php";
require_once "../includes/footer.php";

View File

@@ -14,14 +14,21 @@ if (isset($_GET['client_id'])) {
if (isset($_GET['contact_id'])) {
$contact_id = intval($_GET['contact_id']);
$sql = mysqli_query($mysqli, "SELECT * FROM contacts
$sql = mysqli_query($mysqli, "SELECT * FROM contacts
LEFT JOIN clients ON client_id = contact_client_id
LEFT JOIN locations ON location_id = contact_location_id
LEFT JOIN users ON user_id = contact_user_id
WHERE contact_id = $contact_id
$client_query
LIMIT 1
");
if (mysqli_num_rows($sql) == 0) {
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='javascript:history.back()'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
require_once "../includes/footer.php";
exit();
}
$row = mysqli_fetch_array($sql);
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
@@ -57,12 +64,19 @@ if (isset($_GET['contact_id'])) {
}
// Related Assets Query - 1 to 1 relationship
$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_contact_id = $contact_id ORDER BY asset_name DESC");
$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets
LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1
LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id
LEFT JOIN tags ON tag_id = asset_tag_tag_id
WHERE asset_contact_id = $contact_id
GROUP BY asset_id
ORDER BY asset_name ASC"
);
$asset_count = mysqli_num_rows($sql_related_assets);
// Linked Software Licenses
$sql_linked_software = mysqli_query($mysqli, "SELECT * FROM software_contacts, software
WHERE software_contacts.contact_id = $contact_id
WHERE software_contacts.contact_id = $contact_id
AND software_contacts.software_id = software.software_id
AND software_archived_at IS NULL
ORDER BY software_name ASC"
@@ -83,7 +97,7 @@ if (isset($_GET['contact_id'])) {
LEFT JOIN tags ON tags.tag_id = credential_tags.tag_id
WHERE credential_contact_id = $contact_id
GROUP BY credentials.credential_id
ORDER BY credential_name DESC
ORDER BY credential_name ASC
");
$credential_count = mysqli_num_rows($sql_related_credentials);
@@ -95,7 +109,7 @@ if (isset($_GET['contact_id'])) {
$ticket_count = mysqli_num_rows($sql_related_tickets);
// Related Recurring Tickets Query
$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_tickets
$sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT * FROM recurring_tickets
WHERE recurring_ticket_contact_id = $contact_id
ORDER BY recurring_ticket_next_run DESC"
);
@@ -130,7 +144,7 @@ if (isset($_GET['contact_id'])) {
// Linked Services
$sql_linked_services = mysqli_query($mysqli, "SELECT * FROM service_contacts, services
WHERE service_contacts.contact_id = $contact_id
WHERE service_contacts.contact_id = $contact_id
AND service_contacts.service_id = services.service_id
ORDER BY service_name ASC"
);
@@ -141,7 +155,7 @@ if (isset($_GET['contact_id'])) {
// Linked Documents
$sql_linked_documents = mysqli_query($mysqli, "SELECT * FROM contact_documents, documents
LEFT JOIN users ON document_created_by = user_id
WHERE contact_documents.contact_id = $contact_id
WHERE contact_documents.contact_id = $contact_id
AND contact_documents.document_id = documents.document_id
AND document_archived_at IS NULL
ORDER BY document_name ASC"
@@ -152,7 +166,7 @@ if (isset($_GET['contact_id'])) {
// Linked Files
$sql_linked_files = mysqli_query($mysqli, "SELECT * FROM contact_files, files
WHERE contact_files.contact_id = $contact_id
WHERE contact_files.contact_id = $contact_id
AND contact_files.file_id = files.file_id
AND file_archived_at IS NULL
ORDER BY file_name ASC"
@@ -255,27 +269,27 @@ if (isset($_GET['contact_id'])) {
<div class="dropdown dropleft mr-2">
<button type="button" class="btn btn-primary" data-toggle="dropdown"><i class="fas fa-plus mr-2"></i>New</button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#addTicketModal">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>" data-modal-size="lg">
<i class="fa fa-fw fa-life-ring mr-2"></i>New Ticket
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#addRecurringTicketModal">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/recurring_ticket/recurring_ticket_add.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>" data-modal-size="lg">
<i class="fa fa-fw fa-recycle mr-2"></i>New Recurring Ticket
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#addAssetModal">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/asset/asset_add.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>">
<i class="fa fa-fw fa-desktop mr-2"></i>New Asset
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#addCredentialModal">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/credential/credential_add.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>">
<i class="fa fa-fw fa-key mr-2"></i>New Credential
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#addDocumentModal">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/document/document_add.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>" data-modal-size="lg">
<i class="fa fa-fw fa-file-alt mr-2"></i>New Document
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#uploadFilesModal">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/file/file_upload.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>">
<i class="fa fa-fw fa-upload mr-2"></i>Upload file(s)
</a>
<div class="dropdown-divider"></div>
@@ -394,6 +408,28 @@ if (isset($_GET['contact_id'])) {
$asset_created_at = nullable_htmlentities($row['asset_created_at']);
$device_icon = getAssetIcon($asset_type);
// Tags
$asset_tag_name_display_array = array();
$asset_tag_id_array = array();
$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_asset_tags)) {
$asset_tag_id = intval($row['tag_id']);
$asset_tag_name = nullable_htmlentities($row['tag_name']);
$asset_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($asset_tag_color)) {
$asset_tag_color = "dark";
}
$asset_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($asset_tag_icon)) {
$asset_tag_icon = "tag";
}
$asset_tag_id_array[] = $asset_tag_id;
$asset_tag_name_display_array[] = "<a href='assets.php?$client_url tags[]=$asset_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
?>
<tr>
<th>
@@ -406,6 +442,12 @@ if (isset($_GET['contact_id'])) {
<div class="mt-0">
<small class="text-muted"><?php echo $asset_description; ?></small>
</div>
<?php
if ($asset_tags_display) { ?>
<div class="mt-1">
<?= $asset_tags_display ?>
</div>
<?php } ?>
</th>
<td><?php echo $asset_type; ?></td>
<td>
@@ -431,8 +473,8 @@ if (isset($_GET['contact_id'])) {
<i class="fas fa-fw fa-copy mr-2"></i>Copy
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
href="post.php?unlink_asset_from_contact&contact_id=<?php echo $contact_id; ?>&asset_id=<?php echo $asset_id; ?>"
<a class="dropdown-item"
href="post.php?unlink_asset_from_contact&contact_id=<?php echo $contact_id; ?>&asset_id=<?php echo $asset_id; ?>"
class="btn btn-secondary btn-sm" title="Unlink">
<i class="fas fa-fw fa-unlink mr-2"></i>Unlink
</a>
@@ -571,8 +613,8 @@ if (isset($_GET['contact_id'])) {
<i class="fas fa-fw fa-share-alt mr-2"></i>Share
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
href="post.php?unlink_credential_from_contact&contact_id=<?php echo $contact_id; ?>&credential_id=<?php echo $credential_id; ?>"
<a class="dropdown-item"
href="post.php?unlink_credential_from_contact&contact_id=<?php echo $contact_id; ?>&credential_id=<?php echo $credential_id; ?>"
class="btn btn-secondary btn-sm" title="Unlink">
<i class="fas fa-fw fa-unlink mr-2"></i>Unlink
</a>
@@ -755,7 +797,9 @@ if (isset($_GET['contact_id'])) {
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-life-ring mr-2"></i>Related Tickets</h3>
<div class="card-tools">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTicketModal">
<button type="button" class="btn btn-primary ajax-modal"
data-modal-url="modals/ticket/ticket_add.php?<?= $client_url ?>&contact_id=<?= $contact_id ?>"
data-modal-size="lg">
<i class="fas fa-plus mr-2"></i>New Ticket
</button>
</div>
@@ -1029,7 +1073,7 @@ if (isset($_GET['contact_id'])) {
</div>
</div>
</div>
<div class="card card-dark <?php if ($note_count == 0) { echo "d-none"; } ?>">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-sticky-note mr-2"></i>Notes</h3>
@@ -1172,12 +1216,4 @@ if (isset($_GET['contact_id'])) {
<script src="js/credential_show_otp_via_id.js"></script>
<?php
require_once "modals/ticket/ticket_add.php";
require_once "modals/recurring_ticket/recurring_ticket_add.php";
require_once "modals/asset/asset_add.php";
require_once "modals/credential/credential_add.php";
require_once "modals/document/document_add.php";
require_once "modals/file/file_upload.php";
require_once "../includes/footer.php";

View File

@@ -90,7 +90,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<h3 class="card-title mt-2"><i class="fa fa-fw fa-address-book mr-2"></i>Contacts</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addContactModal">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/contact/contact_add.php?client_id=<?= $client_id ?>">
<i class="fas fa-plus mr-2"></i>New Contact
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
@@ -98,12 +98,14 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php if ($client_url) { ?>
<!-- <a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#contactInviteModal"><i class="fas fa-fw fa-paper-plane mr-2"></i>Invite</a>-->
<!-- <div class="dropdown-divider"></div>-->
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importContactModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/contact/contact_import.php?<?= $client_url ?>">
<i class="fa fa-fw fa-upload mr-2"></i>Import
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportContactModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/contact/contact_export.php?<?= $client_url ?>">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
</div>
@@ -112,7 +114,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
<div class="card-body">
<form autocomplete="off">
<?php if ($client_url) { ?>
<?php if ($client_url) { ?>
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<?php } ?>
<input type="hidden" name="archived" value="<?php echo $archived; ?>">
@@ -134,7 +136,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php
$sql_tags_filter = mysqli_query($mysqli, "
SELECT tags.tag_id, tags.tag_name
FROM tags
FROM tags
LEFT JOIN contact_tags ON contact_tags.tag_id = tags.tag_id
LEFT JOIN contacts ON contact_tags.contact_id = contacts.contact_id
WHERE tag_type = 3
@@ -163,7 +165,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$sql_locations_filter = mysqli_query($mysqli, "
SELECT DISTINCT location_id, location_name
FROM locations
WHERE location_client_id = $client_id
WHERE location_client_id = $client_id
AND ( EXISTS (SELECT 1 FROM contacts WHERE contact_location_id = location_id AND $archive_query) OR location_id = $location_filter)
ORDER BY location_name ASC
");
@@ -187,7 +189,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php
$sql_clients_filter = mysqli_query($mysqli, "
SELECT DISTINCT client_id, client_name
SELECT DISTINCT client_id, client_name
FROM clients
JOIN contacts ON contact_client_id = client_id
WHERE $archive_query
@@ -210,7 +212,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="col-md-3">
<div class="btn-group float-right">
<a href="?<?php echo $client_url; ?>archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
<a href="?<?php echo $client_url; ?>archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived
</a>
@@ -219,29 +221,42 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<?php if ($client_url) { ?>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignLocationModal">
<?php if ($client_url) { ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/contact/contact_bulk_assign_location.php?<?= $client_url ?>"
data-bulk="true">
<i class="fas fa-fw fa-map-marker-alt mr-2"></i>Assign Location
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditPhoneModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/contact/contact_bulk_edit_phone.php"
data-bulk="true">
<i class="fas fa-fw fa-phone-alt mr-2"></i>Set Phone Number
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditDepartmentModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/contact/contact_bulk_edit_department.php"
data-bulk="true">
<i class="fas fa-fw fa-users mr-2"></i>Set Department
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditRoleModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/contact/contact_bulk_edit_role.php"
data-bulk="true">
<i class="fas fa-fw fa-user-shield mr-2"></i>Set Roles
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignTagsModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/contact/contact_bulk_assign_tags.php"
data-bulk="true">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkSendEmailModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/contact/contact_bulk_email.php"
data-modal-size="lg"
data-bulk="true">
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Email
</a>
<?php if ($archived) { ?>
@@ -384,7 +399,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$contact_user_id = intval($row['contact_user_id']);
if ($contact_user_id) {
$user_exists_display = "<span class='badge badge-pill badge-dark p-1' title='User: $auth_method'><i class='fas fa-fw fa-user'></i></span>";
} else {
} else {
$user_exists_display = "";
}
@@ -393,25 +408,25 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
// Asset Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('asset_id') AS num FROM assets WHERE asset_contact_id = $contact_id AND asset_archived_at IS NULL"));
$asset_count = $row['num'];
if ($asset_count) {
if ($asset_count) {
$asset_count_display = "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id#assets' class='mr-2 mb-1 badge badge-pill badge-dark p-2' title='Assets ($asset_count)'><i class='fas fa-fw fa-desktop mr-2'></i>$asset_count</a>";
} else {
$asset_count_display = '';
}
// Credential Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('credential_id') AS num FROM credentials WHERE credential_contact_id = $contact_id AND credential_archived_at IS NULL"));
$credential_count = $row['num'];
if ($credential_count) {
if ($credential_count) {
$credential_count_display = "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id#credentials' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Credentials ($credential_count)'><i class='fas fa-fw fa-key mr-2'></i>$credential_count</a>";
} else {
$credential_count_display = '';
}
// Software Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('software_id') AS num FROM software, software_contacts WHERE software.software_id = software_contacts.software_id AND software_contacts.contact_id = $contact_id AND software_archived_at IS NULL"));
$software_count = $row['num'];
if ($software_count) {
if ($software_count) {
$software_count_display = "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id#software' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Licenses ($software_count)'><i class='fas fa-fw fa-cube mr-2'></i>$software_count</a>";
} else {
$software_count_display = '';
@@ -420,7 +435,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
// Ticket Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets WHERE ticket_contact_id = $contact_id AND ticket_archived_at IS NULL"));
$ticket_count = $row['num'];
if ($ticket_count) {
if ($ticket_count) {
$ticket_count_display = "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id#tickets' class='mr-2 mb-1 badge badge-pill badge-secondary p-2' title='Tickets ($ticket_count)'><i class='fas fa-fw fa-life-ring mr-2'></i>$ticket_count</a>";
} else {
$ticket_count_display = '';
@@ -478,11 +493,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="mt-1">
<?php echo $contact_tags_display; ?>
</div>
<?php } ?>
<?php } ?>
</div>
</div>
</a>
</td>
<td><?php echo $contact_department; ?></td>
<td><?php echo $contact_info_display; ?></td>
@@ -545,63 +560,12 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody>
</table>
</div>
<?php if ($client_url) { require_once "modals/contact/contact_bulk_assign_location.php"; } ?>
<?php require_once "modals/contact/contact_bulk_edit_phone.php"; ?>
<?php require_once "modals/contact/contact_bulk_edit_department.php"; ?>
<?php require_once "modals/contact/contact_bulk_edit_role.php"; ?>
<?php require_once "modals/contact/contact_bulk_assign_tags.php"; ?>
<?php require_once "modals/contact/contact_bulk_email.php"; ?>
</form>
<?php require_once "../includes/filter_footer.php";
?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<!-- JavaScript to Show/Hide Password Form Group -->
<script>
function generatePassword(type, id) {
// Send a GET request to ajax.php as ajax.php?get_readable_pass=true
jQuery.get(
"ajax.php", {
get_readable_pass: 'true'
},
function(data) {
//If we get a response from post.php, parse it as JSON
const password = JSON.parse(data);
// Set the password value to the correct modal, based on the type
if (type == "add") {
document.getElementById("password-add").value = password;
} else if (type == "edit") {
document.getElementById("password-edit-"+id.toString()).value = password;
}
}
);
}
$(document).ready(function() {
$('.authMethod').on('change', function() {
var $form = $(this).closest('.authForm');
if ($(this).val() === 'local') {
$form.find('.passwordGroup').show();
} else {
$form.find('.passwordGroup').hide();
}
});
$('.authMethod').trigger('change');
});
</script>
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/contact/contact_add.php";
require_once "modals/contact/contact_export.php";
if ($client_url) {
require_once "modals/contact/contact_invite.php";
require_once "modals/contact/contact_import.php";
}
require_once "../includes/footer.php";

View File

@@ -106,19 +106,21 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="card-tools">
<?php if (lookupUserPermission("module_credential") >= 2) { ?>
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addCredentialModal" <?php if (!isset($_COOKIE['user_encryption_session_key'])) { echo "disabled"; } ?>>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/credential/credential_add.php?<?= $client_url ?>" <?php if (!isset($_COOKIE['user_encryption_session_key'])) { echo "disabled"; } ?>>
<i class="fas fa-plus mr-2"></i>New Credential
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<?php if ($client_url) { ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importCredentialModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/credential/credential_import.php?<?= $client_url ?>">
<i class="fa fa-fw fa-upload mr-2"></i>Import
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<?php if ($num_rows[0] > 0) { ?>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportCredentialModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/credential/credential_export.php?<?= $client_url ?>">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
<?php } ?>
@@ -151,7 +153,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php
$sql_tags_filter = mysqli_query($mysqli, "
SELECT tags.tag_id, tags.tag_name
FROM tags
FROM tags
LEFT JOIN credential_tags ON credential_tags.tag_id = tags.tag_id
LEFT JOIN credentials ON credential_tags.credential_id = credentials.credential_id
WHERE tag_type = 4
@@ -169,7 +171,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</select>
</div>
</div>
<?php if ($client_url) { ?>
<div class="col-md-2">
<div class="input-group mb-3 mb-md-0">
@@ -198,7 +200,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php
$sql_clients_filter = mysqli_query($mysqli, "
SELECT DISTINCT client_id, client_name
SELECT DISTINCT client_id, client_name
FROM clients
JOIN credentials ON credential_client_id = client_id
WHERE $archive_query
@@ -241,7 +243,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
<?php } else { ?>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignTagsModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/credential/credential_bulk_assign_tags.php"
data-bulk="true">
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
</a>
<div class="dropdown-divider"></div>
@@ -355,7 +359,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
}
$credential_tags_display = implode('', $credential_tag_name_display_array);
if ($credential_contact_id) {
if ($credential_contact_id) {
$credential_contact_display = "<a href='#' class='mr-2 mb-1 badge badge-pill badge-dark p-2 ajax-modal' title='$contact_name'
data-modal-size='lg'
data-modal-url='modals/contact/contact_details.php?id=$credential_contact_id'>
@@ -364,7 +368,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$credential_contact_display = '';
}
if ($credential_asset_id) {
if ($credential_asset_id) {
$credential_asset_display = "<a href='#' class='mr-2 mb-1 badge badge-pill badge-secondary p-2 ajax-modal' title='$asset_name' data-toggle=''
data-modal-size='lg'
data-modal-url='modals/asset/asset_details.php?id=$credential_asset_id'>
@@ -519,25 +523,17 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</tbody>
</table>
</div>
<?php require_once "modals/credential/credential_bulk_assign_tags.php"; ?>
</form>
<?php require_once "../includes/filter_footer.php";
?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<!-- Include script to get TOTP code via the login ID -->
<script src="js/credential_show_otp_via_id.js"></script>
<!-- Include script to generate readable passwords for login entries -->
<script src="js/generate_password.js"></script>
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/credential/credential_add.php";
require_once "modals/credential/credential_export.php";
if ($client_url) {
require_once "modals/credential/credential_import.php";
require_once "modals/share_modal.php";
}
require_once "../includes/footer.php";

View File

@@ -660,7 +660,7 @@ if ($user_config_dashboard_technical_enable == 1) {
<a class="small-box bg-warning" href="domains.php?sort=domain_expire&order=ASC">
<div class="inner">
<h3><?php echo $expiring_domains; ?></h3>
<p>Expiring Domains</p>
<p>Expiring Domains <small>30 Day</small></p>
</div>
<div class="icon">
<i class="fa fa-globe"></i>
@@ -673,7 +673,7 @@ if ($user_config_dashboard_technical_enable == 1) {
<a class="small-box bg-primary" href="certificates.php?sort=certificate_expire&order=ASC">
<div class="inner">
<h3><?php echo $expiring_certificates; ?></h3>
<p>Expiring Certificates</p>
<p>Expiring Certificates<small>30 Day</small></p>
</div>
<div class="icon">
<i class="fa fa-lock"></i>
@@ -729,13 +729,22 @@ if ($user_config_dashboard_technical_enable == 1) {
$client_name = nullable_htmlentities($row['client_name']);
$contact_id = intval($row['ticket_contact_id']);
$contact_name = nullable_htmlentities($row['contact_name']);
if ($client_id) {
$has_client = "&client_id=$client_id";
} else {
$has_client = "";
}
$ticket_priority_color = $ticket_priority == "High" ? "danger" : ($ticket_priority == "Medium" ? "warning" : "info");
$contact_display = empty($contact_name) ? "-" : "<a href='contact_details.php?client_id=$client_id&contact_id=$contact_id'>$contact_name</a>";
?>
<tr class="<?php echo empty($ticket_updated_at) ? 'text-bold' : ''; ?>">
<td><a class="text-dark" href="ticket.php?ticket_id=<?php echo $ticket_id; ?>"><?php echo "$ticket_prefix$ticket_number"; ?></a></td>
<td><a href="ticket.php?ticket_id=<?php echo $ticket_id; ?>"><?php echo $ticket_subject; ?></a></td>
<td>
<a class="text-dark"
href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= "$ticket_prefix$ticket_number" ?>
</a>
</td>
<td><a href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= $ticket_subject ?></a></td>
<td><a href="tickets.php?client_id=<?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong></a></td>
<td><?php echo $contact_display; ?></td>
<td><span class='p-2 badge badge-pill badge-<?php echo $ticket_priority_color; ?>'><?php echo $ticket_priority; ?></span></td>

View File

@@ -17,12 +17,19 @@ if (isset($_GET['document_id'])) {
$folder_location = 0;
$sql_document = mysqli_query($mysqli, "SELECT * FROM documents
$sql_document = mysqli_query($mysqli, "SELECT * FROM documents
LEFT JOIN folders ON document_folder_id = folder_id
LEFT JOIN users ON document_created_by = user_id
WHERE document_client_id = $client_id AND document_id = $document_id"
WHERE document_client_id = $client_id AND document_id = $document_id
LIMIT 1"
);
if (mysqli_num_rows($sql_document) == 0) {
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='javascript:history.back()'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
require_once "../includes/footer.php";
exit();
}
$row = mysqli_fetch_array($sql_document);
$folder_name = nullable_htmlentities($row['folder_name']);
@@ -44,10 +51,10 @@ $page_title = $row['document_name'];
<ol class="breadcrumb d-print-none">
<li class="breadcrumb-item">
<a href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
<a href="client_overview.php?client_id=<?= $client_id ?>"><?= $client_name ?></a>
</li>
<li class="breadcrumb-item">
<a href="documents.php?client_id=<?php echo $client_id; ?>">Documents</a>
<a href="files.php?client_id=<?= $client_id ?>">Files</a>
</li>
<?php
// Build the full folder path
@@ -77,7 +84,7 @@ $page_title = $row['document_name'];
$bread_crumb_folder_name = $folder['folder_name']; // Sanitized before put in array
?>
<li class="breadcrumb-item">
<a href="documents.php?client_id=<?php echo $client_id; ?>&folder_id=<?php echo $bread_crumb_folder_id; ?>">
<a href="files.php?client_id=<?php echo $client_id; ?>&folder_id=<?php echo $bread_crumb_folder_id; ?>">
<i class="fas fa-fw fa-folder-open mr-2"></i><?php echo $bread_crumb_folder_name; ?>
</a>
</li>
@@ -85,9 +92,9 @@ $page_title = $row['document_name'];
}
?>
<li class="breadcrumb-item active">
<i class="fas fa-file"></i> <?php echo $document_name; ?>
<?php if (!empty($document_archived_at)) {
echo "<span class='text-danger ml-2'>(ARCHIVED on $document_archived_at)</span>";
<i class="fas fa-file"></i> <?php echo $document_name; ?>
<?php if (!empty($document_archived_at)) {
echo "<span class='text-danger ml-2'>(ARCHIVED on $document_archived_at)</span>";
} ?>
</li>
</ol>
@@ -97,18 +104,31 @@ $page_title = $row['document_name'];
<div class="col-md-9">
<div class="card">
<div class="card-header bg-dark">
<h3><?php echo $document_name; ?> <?php if (!empty($document_description)) { ?><span class="h6 text-muted">(<?php echo $document_description; ?>)</span><?php } ?></h3>
<div class="row">
<div class="col"><strong>Date:</strong> <?php echo date('Y-m-d', strtotime($document_created_at)); ?></div>
<?php if(!empty($document_created_by_name)){ ?>
<div class="col"><strong>Prepared By:</strong> <?php echo $document_created_by_name; ?></div>
<?php } ?>
<div class="col">
<div class="h4 mb-0"><?= $document_name ?></div>
<?php if ($document_description) { ?>
<div class="text-light"><?= $document_description ?></div>
<?php } ?>
</div>
<div class="col">
<div class="float-right">
<div>
Date:
<strong><?= date('Y-m-d', strtotime($document_created_at)); ?></strong>
</div>
<?php if($document_created_by_name) { ?>
<div>
Prepared By:
<strong><?= $document_created_by_name ?></strong>
</div>
<?php } ?>
</div>
</div>
</div>
</div>
<div class="card-body prettyContent">
<?php echo $document_content; ?>
<?= $document_content ?>
<hr>
<h4>Documentation Revision History</h4>
@@ -144,15 +164,15 @@ $page_title = $row['document_name'];
?>
<tr>
<td><?php echo $document_version_count; ?></td>
<td><?php echo $document_version_created_date; ?></td>
<td><?php echo $document_version_name; ?></td>
<td><?php echo $document_version_description_display; ?></td>
<td><?php echo $document_version_author; ?></td>
<td><?= $document_version_count ?></td>
<td><?= $document_version_created_date ?></td>
<td><?= $document_version_name ?></td>
<td><?= $document_version_description_display ?></td>
<td><?= $document_version_author ?></td>
</tr>
<?php
<?php
$document_version_count++; // Increment the counter
}
}
?>
</tbody>
</table>
@@ -163,30 +183,33 @@ $page_title = $row['document_name'];
<div class="col-md-3 d-print-none">
<div class="row">
<div class="col-12 mb-3">
<button type="button" class="btn btn-primary ajax-modal mr-2"
<button type="button" class="btn btn-primary ajax-modal mr-1"
data-modal-size="lg"
data-modal-url="modals/document/document_edit.php?id=<?= $document_id ?>">
<i class="fas fa-fw fa-edit"></i>
<i class="fas fa-fw fa-edit" title="Edit"></i>
</button>
<button type="button" class="btn btn-secondary mr-2" data-toggle="modal" data-target="#shareModal"
onclick="populateShareModal(<?php echo "$client_id, 'Document', $document_id"; ?>)">
<i class="fas fa-fw fa-share"></i>
<button type="button" class="btn btn-secondary mr-1" data-toggle="modal" data-target="#shareModal"
onclick="populateShareModal(<?= "$client_id, 'Document', $document_id"; ?>)">
<i class="fas fa-fw fa-share" title="Share"></i>
</button>
<a class="btn btn-success mr-2" href="post.php?export_document=<?php echo $document_id; ?>"><i class='fas fa-fw fa-file-pdf'></i></a>
<button type="button" class="btn btn-secondary" onclick="window.print();"><i class="fas fa-fw fa-print"></i></button>
<a class="btn btn-success mr-1" href="post.php?export_document=<?= $document_id ?>"><i class='fas fa-fw fa-file-pdf' title="PDF Export"></i></a>
<button type="button" class="btn btn-secondary mr-4" onclick="window.print();"><i class="fas fa-fw fa-print" title="Print"></i></button>
<a class="btn btn-warning mr-1 confirm-link" href="post.php?archive_document=<?= $document_id ?>" title="Archive"><i class='fas fa-fw fa-archive'></i></a>
<a class="btn btn-danger confirm-link" href="post.php?delete_document=<?= $document_id ?>&from=document_details" title="Delete"><i class='fas fa-fw fa-trash-alt'></i></a>
</div>
</div>
<div class="card card-body bg-light">
<h5 class="mb-3"><i class="fas fa-tags mr-2"></i>Related Items</h5>
<h6>
<i class="fas fa-fw fa-paperclip text-secondary mr-2"></i>Files
<button type="button" class="btn btn-link btn-sm" data-toggle="modal" data-target="#linkFileToDocumentModal">
<button type="button" class="btn btn-link btn-sm ajax-modal"
data-modal-url="modals/document/document_link_file.php?document_id=<?= $document_id ?>">
<i class="fas fa-fw fa-plus"></i>
</button>
</h6>
<?php
$sql_files = mysqli_query($mysqli, "SELECT * FROM files, document_files
WHERE document_files.file_id = files.file_id
WHERE document_files.file_id = files.file_id
AND document_files.document_id = $document_id
ORDER BY file_name ASC"
);
@@ -202,9 +225,9 @@ $page_title = $row['document_name'];
?>
<div class="ml-2">
<a href="files.php?client_id=<?php echo $client_id; ?>&folder_id=<?php echo $folder_id; ?>&q=<?php echo $file_name; ?>" target="_blank"><?php echo $file_name; ?></a>
<a class="confirm-link" href="post.php?unlink_file_from_document&file_id=<?php echo $file_id; ?>&document_id=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-trash-alt text-secondary float-right"></i>
<a href="files.php?client_id=<?= $client_id ?>&folder_id=<?= $folder_id ?>&q=<?= $file_name ?>" target="_blank"><?= $file_name ?></a>
<a class="confirm-link" href="post.php?unlink_file_from_document&file_id=<?= $file_id ?>&document_id=<?= $document_id ?>">
<i class="fas fa-fw fa-unlink text-secondary float-right" title="Unlink File"></i>
</a>
</div>
<?php
@@ -212,13 +235,14 @@ $page_title = $row['document_name'];
?>
<h6>
<i class="fas fa-fw fa-users text-secondary mt-3 mr-2"></i>Contacts
<button type="button" class="btn btn-link btn-sm" data-toggle="modal" data-target="#linkContactToDocumentModal">
<button type="button" class="btn btn-link btn-sm ajax-modal"
data-modal-url="modals/document/document_link_contact.php?document_id=<?= $document_id ?>">
<i class="fas fa-fw fa-plus"></i>
</button>
</h6>
<?php
$sql_contacts = mysqli_query($mysqli, "SELECT contacts.contact_id, contact_name FROM contacts, contact_documents
WHERE contacts.contact_id = contact_documents.contact_id
WHERE contacts.contact_id = contact_documents.contact_id
AND contact_documents.document_id = $document_id
ORDER BY contact_name ASC"
);
@@ -238,7 +262,7 @@ $page_title = $row['document_name'];
data-modal-url="modals/contact/contact_details.php?id=<?= $contact_id ?>">
<?php echo $contact_name; ?></a>
<a class="confirm-link float-right" href="post.php?unlink_contact_from_document&contact_id=<?php echo $contact_id; ?>&document_id=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-trash-alt text-secondary"></i>
<i class="fas fa-fw fa-unlink text-secondary" title="Unlink Contact"></i>
</a>
</div>
<?php
@@ -246,7 +270,7 @@ $page_title = $row['document_name'];
?>
<h6>
<i class="fas fa-fw fa-laptop text-secondary mr-2 mt-3"></i>Assets
<button type="button" class="btn btn-link btn-sm" data-toggle="modal" data-target="#linkAssetToDocumentModal">
<button type="button" class="btn btn-link btn-sm ajax-modal" data-modal-url="modals/document/document_link_asset.php?document_id=<?= $document_id ?>">
<i class="fas fa-fw fa-plus"></i>
</button>
</h6>
@@ -273,7 +297,7 @@ $page_title = $row['document_name'];
<?php echo $asset_name; ?>
</a>
<a class="confirm-link float-right" href="post.php?unlink_asset_from_document&asset_id=<?php echo $asset_id; ?>&document_id=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-trash-alt text-secondary"></i>
<i class="fas fa-fw fa-unlink text-secondary" title="Unlink Asset"></i>
</a>
</div>
<?php
@@ -281,13 +305,14 @@ $page_title = $row['document_name'];
?>
<h6>
<i class="fas fa-fw fa-cube text-secondary mr-2 mt-3"></i>Licenses
<button type="button" class="btn btn-link btn-sm" data-toggle="modal" data-target="#linkSoftwareToDocumentModal">
<button type="button" class="btn btn-link btn-sm ajax-modal"
data-modal-url="modals/document/document_link_software.php?document_id=<?= $document_id ?>">
<i class="fas fa-fw fa-plus"></i>
</button>
</h6>
<?php
$sql_software = mysqli_query($mysqli, "SELECT software.software_id, software_name FROM software, software_documents
WHERE software.software_id = software_documents.software_id
WHERE software.software_id = software_documents.software_id
AND software_documents.document_id = $document_id
ORDER BY software_name ASC"
);
@@ -304,7 +329,7 @@ $page_title = $row['document_name'];
<div class="ml-2">
<a href="software.php?client_id=<?php echo $client_id; ?>&q=<?php echo $software_name; ?>" target="_blank"><?php echo $software_name; ?></a>
<a class="confirm-link float-right" href="post.php?unlink_software_from_document&software_id=<?php echo $software_id; ?>&document_id=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-trash-alt text-secondary"></i>
<i class="fas fa-fw fa-unlink text-secondary" title="Unlink License"></i>
</a>
</div>
<?php
@@ -312,13 +337,14 @@ $page_title = $row['document_name'];
?>
<h6>
<i class="fas fa-fw fa-building text-secondary mr-2 mt-3"></i>Vendors
<button type="button" class="btn btn-link btn-sm" data-toggle="modal" data-target="#linkVendorToDocumentModal">
<button type="button" class="btn btn-link btn-sm ajax-modal"
data-modal-url="modals/document/document_link_vendor.php?document_id=<?= $document_id ?>">
<i class="fas fa-fw fa-plus"></i>
</button>
</h6>
<?php
$sql_vendors = mysqli_query($mysqli, "SELECT vendors.vendor_id, vendor_name FROM vendors, vendor_documents
WHERE vendors.vendor_id = vendor_documents.vendor_id
WHERE vendors.vendor_id = vendor_documents.vendor_id
AND vendor_documents.document_id = $document_id
ORDER BY vendor_name ASC"
);
@@ -334,10 +360,10 @@ $page_title = $row['document_name'];
?>
<div class="ml-2">
<a class="ajax-modal" href="#" data-modal-url="modals/vendor/vendor_details.php?id=<?= $vendor_id ?>">
<?php echo $vendor_name; ?>
<?php echo $vendor_name; ?>
</a>
<a class="confirm-link float-right" href="post.php?unlink_vendor_from_document&vendor_id=<?php echo $vendor_id; ?>&document_id=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-trash-alt text-secondary"></i>
<i class="fas fa-fw fa-unlink text-secondary" title="Unlink Vendor"></i>
</a>
</div>
<?php
@@ -350,7 +376,8 @@ $page_title = $row['document_name'];
<h6><i class="fas fa-handshake mr-2"></i>Portal Collaboration</h6>
<div class="mt-1">
<i class="fa fa-fw fa-eye<?php if (!$document_client_visible) { echo '-slash'; } ?> text-secondary mr-2"></i>Document is
<a href="#" data-toggle="modal" data-target="#editDocumentClientVisibileModal">
<a class="ajax-modal" href="#"
data-modal-url="modals/document/document_edit_visibility.php?document_id=<?= $document_id ?>">
<?php
if ($document_client_visible) {
echo "<span class='text-bold text-dark'>visible</span>";
@@ -405,11 +432,5 @@ $page_title = $row['document_name'];
<?php
require_once "modals/document/document_link_file.php";
require_once "modals/document/document_link_contact.php";
require_once "modals/document/document_link_asset.php";
require_once "modals/document/document_link_software.php";
require_once "modals/document/document_link_vendor.php";
require_once "modals/document/document_edit_visibility.php";
require_once "modals/share_modal.php";
require_once "../includes/footer.php";

View File

@@ -1,484 +0,0 @@
<?php
// Default Column Sortby Filter
$sort = "document_name";
$order = "ASC";
require_once "includes/inc_all_client.php";
// Perms
enforceUserPermission('module_support');
// Folder
if (!empty($_GET['folder_id'])) {
$folder = intval($_GET['folder_id']);
} else {
$folder = 0;
}
// Search query SQL snippet
if (!empty($q)) {
$query_snippet = "AND (MATCH(document_content_raw) AGAINST ('$q') OR document_name LIKE '%$q%')";
} else {
$query_snippet = ""; // empty
}
//Rebuild URL
$url_query_strings_sort = http_build_query($get_copy);
// Folder ID
$get_folder_id = 0;
if (!empty($_GET['folder_id'])) {
$get_folder_id = intval($_GET['folder_id']);
}
// Set Folder Location Var used when creating folders
$folder_location = 0;
if ($get_folder_id == 0 && isset($_GET["q"])) {
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM documents
LEFT JOIN users ON document_created_by = user_id
WHERE document_client_id = $client_id
AND document_archived_at IS NULL
$query_snippet
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}else{
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM documents
LEFT JOIN users ON document_created_by = user_id
WHERE document_client_id = $client_id
AND document_folder_id = $folder
AND document_archived_at IS NULL
$query_snippet
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
// Breadcrumbs
// Build the full folder path
$folder_id = $get_folder_id;
$folder_path = array();
while ($folder_id > 0) {
$sql_folder = mysqli_query($mysqli, "SELECT folder_name, parent_folder FROM folders WHERE folder_id = $folder_id");
if ($row_folder = mysqli_fetch_assoc($sql_folder)) {
$folder_name = nullable_htmlentities($row_folder['folder_name']);
$parent_folder = intval($row_folder['parent_folder']);
// Prepend the folder to the beginning of the array
array_unshift($folder_path, array('folder_id' => $folder_id, 'folder_name' => $folder_name));
// Move up to the parent folder
$folder_id = $parent_folder;
} else {
// If the folder is not found, break the loop
break;
}
}
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2">
<i class="fa fa-fw fa-folder mr-2"></i>Documents
</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addDocumentModal">
<i class="fas fa-plus mr-2"></i>New Document
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#createFolderModal">
<i class="fa fa-fw fa-folder-plus mr-2"></i>New Folder
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#addDocumentFromTemplateModal">From Template</a>
</div>
</div>
</div>
</div>
<div class="card-body">
<form autocomplete="off">
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<input type="hidden" name="folder_id" value="<?php echo $get_folder_id; ?>">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search documents in <?php if($get_folder_id == 0) { echo "all folders"; } else { echo "current folder"; } ?>">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<div class="col-md-8">
<div class="btn-group float-right">
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkMoveDocumentModal">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_documents">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
</div>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="row">
<div class="col-md-3 border-right mb-3">
<h4>Folders</h4>
<hr>
<ul class="nav nav-pills flex-column bg-light">
<li class="nav-item">
<div class="row">
<div class="col-10">
<?php
// Get a count of documents that have no folder
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('document_id') AS num FROM documents WHERE document_folder_id = 0 AND document_client_id = $client_id AND document_archived_at IS NULL"));
$num_documents = intval($row['num']);
?>
<a class="nav-link <?php if ($get_folder_id == 0) { echo "active"; } ?>" href="?client_id=<?php echo $client_id; ?>&folder_id=0">
/ <?php if ($num_documents > 0) { echo "<span class='badge badge-pill badge-dark float-right mt-1'>$num_documents</span>"; } ?>
</a>
</div>
<div class="col-2">
</div>
</div>
</li>
<?php
// Function to check if a folder is an ancestor of the current folder
function is_ancestor_folder($folder_id, $current_folder_id, $client_id) {
global $mysqli;
// Base case: if current_folder_id is 0 or equal to folder_id
if ($current_folder_id == 0) {
return false;
}
if ($current_folder_id == $folder_id) {
return true;
}
// Get the parent folder of the current folder
$result = mysqli_query($mysqli, "SELECT parent_folder FROM folders WHERE folder_id = $current_folder_id AND folder_client_id = $client_id");
if ($row = mysqli_fetch_assoc($result)) {
$parent_folder_id = intval($row['parent_folder']);
// Recursive call to check the parent folder
return is_ancestor_folder($folder_id, $parent_folder_id, $client_id);
} else {
// Folder not found
return false;
}
}
// Recursive function to display folders and subfolders
function display_folders($parent_folder_id, $client_id, $indent = 0) {
global $mysqli, $get_folder_id, $session_user_role;
$sql_folders = mysqli_query($mysqli, "SELECT * FROM folders WHERE parent_folder = $parent_folder_id AND folder_location = 0 AND folder_client_id = $client_id ORDER BY folder_name ASC");
while ($row = mysqli_fetch_array($sql_folders)) {
$folder_id = intval($row['folder_id']);
$folder_name = nullable_htmlentities($row['folder_name']);
// Get the number of documents in the folder
$row2 = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('document_id') AS num FROM documents WHERE document_folder_id = $folder_id AND document_archived_at IS NULL"));
$num_documents = intval($row2['num']);
// Get the number of subfolders
$subfolder_result = mysqli_query($mysqli, "SELECT COUNT(*) AS count FROM folders WHERE parent_folder = $folder_id AND folder_client_id = $client_id");
$subfolder_count = intval(mysqli_fetch_assoc($subfolder_result)['count']);
echo '<li class="nav-item">';
echo '<div class="row">';
echo '<div class="col-10">';
echo '<a class="nav-link ';
if ($get_folder_id == $folder_id) { echo "active"; }
echo '" href="?client_id=' . $client_id . '&folder_id=' . $folder_id . '">';
// Indentation for subfolders
echo str_repeat('&nbsp;', $indent * 4);
// Determine if the folder is open
if ($get_folder_id == $folder_id || is_ancestor_folder($folder_id, $get_folder_id, $client_id)) {
echo '<i class="fas fa-fw fa-folder-open"></i>';
} else {
echo '<i class="fas fa-fw fa-folder"></i>';
}
echo ' ' . $folder_name;
if ($num_documents > 0) {
echo "<span class='badge badge-pill badge-dark float-right mt-1'>$num_documents</span>";
}
echo '</a>';
echo '</div>';
echo '<div class="col-2">';
?>
<div class="dropdown">
<button class="btn btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/folder/folder_rename.php?id=<?= $folder_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<?php
// Only show delete option if user is admin, folder has no documents, and no subfolders
if ($session_user_role == 3 && $num_documents == 0 && $subfolder_count == 0) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_folder=<?php echo $folder_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
<?php
echo '</div>';
echo '</div>';
if ($subfolder_count > 0) {
// Display subfolders
echo '<ul class="nav nav-pills flex-column bg-light">';
display_folders($folder_id, $client_id, $indent + 1);
echo '</ul>';
}
echo '</li>';
}
}
// Start displaying folders from the root (parent_folder = 0)
display_folders(0, $client_id);
?>
</ul>
<?php require_once "modals/folder/folder_add.php"; ?>
</div>
<div class="col-md-9">
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="?client_id=<?php echo $client_id; ?>&folder_id=0">
<i class="fas fa-fw fa-folder mr-2"></i>Root
</a>
</li>
<?php
// Output breadcrumb items for each folder in the path
foreach ($folder_path as $folder) {
$bread_crumb_folder_id = $folder['folder_id']; // Already Sanitized before it was pushed into array
$bread_crumb_folder_name = $folder['folder_name']; // Already Sanitized before it was pushed into array
?>
<li class="breadcrumb-item">
<a href="?client_id=<?php echo $client_id; ?>&folder_id=<?php echo $bread_crumb_folder_id; ?>">
<i class="fas fa-fw fa-folder-open mr-2"></i><?php echo $bread_crumb_folder_name; ?>
</a>
</li>
<?php
}
?>
</ol>
</nav>
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="table-responsive-sm">
<table class="table table-border">
<thead class="thead-light <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=document_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'document_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=document_created_at&order=<?php echo $disp; ?>">
Created <?php if ($sort == 'document_created_at') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=document_updated_at&order=<?php echo $disp; ?>">
Last Update <?php if ($sort == 'document_updated_at') { echo $order_icon; } ?>
</a>
</th>
<th></th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$document_id = intval($row['document_id']);
$document_name = nullable_htmlentities($row['document_name']);
$document_description = nullable_htmlentities($row['document_description']);
$document_content = nullable_htmlentities($row['document_content']);
$document_created_by_name = nullable_htmlentities($row['user_name']);
$document_created_at = date("m/d/Y",strtotime($row['document_created_at']));
if ($row['document_updated_at']) {
$document_updated_at_display = date("m/d/Y",strtotime($row['document_updated_at']));
} else {
$document_updated_at_display = "-";
}
$document_folder_id = intval($row['document_folder_id']);
// Check if shared
$sql_shared = mysqli_query(
$mysqli,
"SELECT * FROM shared_items
WHERE item_client_id = $client_id
AND item_active = 1
AND item_views != item_view_limit
AND item_expire_at > NOW()
AND item_type = 'Document'
AND item_related_id = $document_id
LIMIT 1"
);
$row = mysqli_fetch_array($sql_shared);
if($row) {
$item_id = intval($row['item_id']);
$item_active = nullable_htmlentities($row['item_active']);
$item_key = nullable_htmlentities($row['item_key']);
$item_type = nullable_htmlentities($row['item_type']);
$item_related_id = intval($row['item_related_id']);
$item_note = nullable_htmlentities($row['item_note']);
$item_recipient = nullable_htmlentities($row['item_recipient']);
$item_views = nullable_htmlentities($row['item_views']);
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
$item_created_at = nullable_htmlentities($row['item_created_at']);
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
$item_expire_at_human = timeAgo($row['item_expire_at']);
}
?>
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="document_ids[]" value="<?php echo $document_id ?>">
</div>
</td>
<td>
<a href="document_details.php?client_id=<?php echo $client_id; ?>&document_id=<?php echo $document_id; ?>"><i class="fas fa-fw fa-file-alt"></i> <?php echo $document_name; ?></a>
<div class="text-secondary mt-1"><?php echo $document_description; ?>
</td>
<td>
<?php echo $document_created_at; ?>
<div class="text-secondary mt-1"><?php echo $document_created_by_name; ?>
</td>
<td><?php echo $document_updated_at_display; ?></td>
<td>
<?php if (mysqli_num_rows($sql_shared) > 0) { ?>
<div class="media" title="Expires <?php echo $item_expire_at_human; ?>">
<i class="fas fa-link mr-2 mt-1"></i>
<div class="media-body">Shared
<br>
<small class="text-secondary"><?php echo $item_recipient; ?></small>
</div>
</div>
<?php } ?>
</td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/document/document_view.php?id=<?= $document_id ?>">
<i class="fas fa-fw fa-eye mr-2"></i>Quick View
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/document/document_edit.php?id=<?= $document_id ?>">
<i class="fas fa-fw fa-pencil-alt mr-2"></i>Edit
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#shareModal" onclick="populateShareModal(<?php echo "$client_id, 'Document', $document_id"; ?>)">
<i class="fas fa-fw fa-share mr-2"></i>Share
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/document/document_rename.php?id=<?= $document_id ?>">
<i class="fas fa-fw fa-pencil-alt mr-2"></i>Rename
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/document/document_move.php?id=<?= $document_id ?>">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_document=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_document=<?php echo $document_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
<br>
</div>
<?php require_once "modals/document/document_bulk_move.php"; ?>
</form>
<?php require_once "../includes/filter_footer.php";
?>
</div>
</div>
</div>
</div>
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/share_modal.php";
require_once "modals/document/document_add.php";
require_once "modals/document/document_add_from_template.php";
require_once "../includes/footer.php";

View File

@@ -71,301 +71,297 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-globe mr-2"></i>Domains</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addDomainModal"><i class="fas fa-plus mr-2"></i>New Domain</button>
<?php if ($num_rows[0] > 0) { ?>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportDomainModal">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
</div>
<?php } ?>
</div>
</div>
</div>
<div class="card-body">
<form autocomplete="off">
<?php if ($client_url) { ?>
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-globe mr-2"></i>Domains</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/domain/domain_add.php?<?= $client_url ?>"><i class="fas fa-plus mr-2"></i>New Domain</button>
<?php if ($num_rows[0] > 0) { ?>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/domain/domain_export.php?<?= $client_url ?>">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
</div>
<?php } ?>
<input type="hidden" name="archived" value="<?php echo $archived; ?>">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Domains">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<?php if ($client_url) { ?>
<div class="col-md-2"></div>
<?php } else { ?>
<div class="col-md-2">
<div class="input-group mb-3 mb-md-0">
<select class="form-control select2" name="client" onchange="this.form.submit()">
<option value="" <?php if ($client == "") { echo "selected"; } ?>>- All Clients -</option>
<?php
$sql_clients_filter = mysqli_query($mysqli, "
SELECT DISTINCT client_id, client_name
FROM clients
JOIN domains ON domain_client_id = client_id
WHERE $archive_query
$access_permission_query
ORDER BY client_name ASC
");
while ($row = mysqli_fetch_array($sql_clients_filter)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<option <?php if ($client == $client_id) { echo "selected"; } ?> value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
<?php
}
?>
</select>
</div>
</div>
<?php } ?>
<div class="col-md-6">
<div class="btn-group float-right">
<a href="?<?php echo $client_url; ?>archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived
</a>
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<?php if ($archived) { ?>
<button class="dropdown-item text-info"
type="submit" form="bulkActions" name="bulk_unarchive_domains">
<i class="fas fa-fw fa-redo mr-2"></i>Unarchive
</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_domains">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
<?php } else { ?>
<button class="dropdown-item text-danger confirm-link"
type="submit" form="bulkActions" name="bulk_archive_domains">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</button>
<?php } ?>
</div>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<?php if ($client_url) { ?>
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<?php } ?>
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?> text-nowrap">
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=domain_name&order=<?php echo $disp; ?>">
Domain <?php if ($sort == 'domain_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=registrar_name&order=<?php echo $disp; ?>">
Registrar <?php if ($sort == 'registrar_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=webhost_name&order=<?php echo $disp; ?>">
Web Host <?php if ($sort == 'webhost_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=dnshost_name&order=<?php echo $disp; ?>">
DNS Host <?php if ($sort == 'dnshost_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=mailhost_name&order=<?php echo $disp; ?>">
Mail Host <?php if ($sort == 'mailhost_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=domain_expire&order=<?php echo $disp; ?>">
Expires <?php if ($sort == 'domain_expire') { echo $order_icon; } ?>
</a>
</th>
<?php if (!$client_url) { ?>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'client_name') { echo $order_icon; } ?>
</a>
</th>
<?php } ?>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$domain_id = intval($row['domain_id']);
$domain_name = nullable_htmlentities($row['domain_name']);
$domain_description = nullable_htmlentities($row['domain_description']);
$domain_expire = nullable_htmlentities($row['domain_expire']);
$domain_expire_ago = timeAgo($domain_expire);
// Convert the expiry date to a timestamp
$domain_expire_timestamp = strtotime($row['domain_expire'] ?? '');
$current_timestamp = time(); // Get current timestamp
// Calculate the difference in days
$days_until_expiry = ($domain_expire_timestamp - $current_timestamp) / (60 * 60 * 24);
// Determine the class based on the number of days until expiry
if ($days_until_expiry <= 0) {
$tr_class = "table-secondary";
} elseif ($days_until_expiry <= 14) {
$tr_class = "table-danger";
} elseif ($days_until_expiry <= 90) {
$tr_class = "table-warning";
} else {
$tr_class = '';
}
$domain_registrar_id = intval($row['registrar_id']);
$domain_webhost_id = intval($row['webhost_id']);
$domain_dnshost_id = intval($row['dnshost_id']);
$domain_mailhost_id = intval($row['mailhost_id']);
$domain_registrar_name = nullable_htmlentities($row['registrar_name']);
$domain_webhost_name = nullable_htmlentities($row['webhost_name']);
$domain_dnshost_name = nullable_htmlentities($row['dnshost_name']);
$domain_mailhost_name = nullable_htmlentities($row['mailhost_name']);
$domain_created_at = nullable_htmlentities($row['domain_created_at']);
$domain_archived_at = nullable_htmlentities($row['domain_archived_at']);
$client_id = intval($row['domain_client_id']);
$client_name = nullable_htmlentities($row['client_name']);
// Add - if empty on the table
$domain_registrar_name_display = $domain_registrar_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_registrar_id'>
$domain_registrar_name
</a>" : "-";
$domain_webhost_name_display = $domain_webhost_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_webhost_id'>
$domain_webhost_name
</a>" : "-";
$domain_dnshost_name_display = $domain_dnshost_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_dnshost_id'>
$domain_dnshost_name
</a>" : "-";
$domain_mailhost_name_display = $domain_mailhost_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_mailhost_id'>
$domain_mailhost_name
</a>" : "-";
?>
<tr class="<?php echo $tr_class; ?>">
<td class="pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="domain_ids[]" value="<?php echo $domain_id ?>">
</div>
</td>
<td class="">
<a class="text-dark ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/domain/domain_edit.php?<?= $client_url ?>&id=<?= $domain_id ?>">
<div class="media">
<i class="fa fa-fw fa-2x fa-globe mr-3"></i>
<div class="media-body">
<div><?php echo $domain_name; ?></div>
<div><small class="text-secondary"><?php echo $domain_description; ?></small></div>
</div>
</div>
</a>
</td>
<td><?php echo $domain_registrar_name_display; ?></td>
<td><?php echo $domain_webhost_name_display; ?></td>
<td><?php echo $domain_dnshost_name_display; ?></td>
<td><?php echo $domain_mailhost_name_display; ?></td>
<td>
<div><?php echo $domain_expire; ?></div>
<div><small><?php echo $domain_expire_ago; ?></small></div>
</td>
<?php if (!$client_url) { ?>
<td><a href="domains.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
<?php } ?>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/domain/domain_edit.php?<?= $client_url ?>&id=<?= $domain_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<?php if ($session_user_role == 3) { ?>
<?php if ($domain_archived_at) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-info confirm-link" href="post.php?unarchive_domain=<?php echo $domain_id; ?>">
<i class="fas fa-fw fa-redo mr-2"></i>Unarchive
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_domain=<?php echo $domain_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } else { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_domain=<?php echo $domain_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php } ?>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</form>
</div>
<?php require_once "../includes/filter_footer.php";
?>
</div>
</div>
<?php
require_once "modals/domain/domain_add.php";
require_once "modals/domain/domain_export.php";
?>
<div class="card-body">
<form autocomplete="off">
<?php if ($client_url) { ?>
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<?php } ?>
<input type="hidden" name="archived" value="<?php echo $archived; ?>">
<div class="row">
<div class="col-md-4">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Domains">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<?php if ($client_url) { ?>
<div class="col-md-2"></div>
<?php } else { ?>
<div class="col-md-2">
<div class="input-group mb-3 mb-md-0">
<select class="form-control select2" name="client" onchange="this.form.submit()">
<option value="" <?php if ($client == "") { echo "selected"; } ?>>- All Clients -</option>
<?php
$sql_clients_filter = mysqli_query($mysqli, "
SELECT DISTINCT client_id, client_name
FROM clients
JOIN domains ON domain_client_id = client_id
WHERE $archive_query
$access_permission_query
ORDER BY client_name ASC
");
while ($row = mysqli_fetch_array($sql_clients_filter)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<option <?php if ($client == $client_id) { echo "selected"; } ?> value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
<?php
}
?>
</select>
</div>
</div>
<?php } ?>
<div class="col-md-6">
<div class="btn-group float-right">
<a href="?<?php echo $client_url; ?>archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
<i class="fa fa-fw fa-archive mr-2"></i>Archived
</a>
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<?php if ($archived) { ?>
<button class="dropdown-item text-info"
type="submit" form="bulkActions" name="bulk_unarchive_domains">
<i class="fas fa-fw fa-redo mr-2"></i>Unarchive
</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_domains">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
<?php } else { ?>
<button class="dropdown-item text-danger confirm-link"
type="submit" form="bulkActions" name="bulk_archive_domains">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</button>
<?php } ?>
</div>
</div>
</div>
</div>
</div>
</form>
<hr>
<div class="table-responsive-sm">
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<?php if ($client_url) { ?>
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<?php } ?>
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?> text-nowrap">
<tr>
<td class="pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=domain_name&order=<?php echo $disp; ?>">
Domain <?php if ($sort == 'domain_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=registrar_name&order=<?php echo $disp; ?>">
Registrar <?php if ($sort == 'registrar_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=webhost_name&order=<?php echo $disp; ?>">
Web Host <?php if ($sort == 'webhost_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=dnshost_name&order=<?php echo $disp; ?>">
DNS Host <?php if ($sort == 'dnshost_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=mailhost_name&order=<?php echo $disp; ?>">
Mail Host <?php if ($sort == 'mailhost_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=domain_expire&order=<?php echo $disp; ?>">
Expires <?php if ($sort == 'domain_expire') { echo $order_icon; } ?>
</a>
</th>
<?php if (!$client_url) { ?>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'client_name') { echo $order_icon; } ?>
</a>
</th>
<?php } ?>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$domain_id = intval($row['domain_id']);
$domain_name = nullable_htmlentities($row['domain_name']);
$domain_description = nullable_htmlentities($row['domain_description']);
$domain_expire = nullable_htmlentities($row['domain_expire']);
$domain_expire_ago = timeAgo($domain_expire);
// Convert the expiry date to a timestamp
$domain_expire_timestamp = strtotime($row['domain_expire'] ?? '');
$current_timestamp = time(); // Get current timestamp
// Calculate the difference in days
$days_until_expiry = ($domain_expire_timestamp - $current_timestamp) / (60 * 60 * 24);
// Determine the class based on the number of days until expiry
if ($days_until_expiry <= 0) {
$tr_class = "table-secondary";
} elseif ($days_until_expiry <= 14) {
$tr_class = "table-danger";
} elseif ($days_until_expiry <= 90) {
$tr_class = "table-warning";
} else {
$tr_class = '';
}
$domain_registrar_id = intval($row['registrar_id']);
$domain_webhost_id = intval($row['webhost_id']);
$domain_dnshost_id = intval($row['dnshost_id']);
$domain_mailhost_id = intval($row['mailhost_id']);
$domain_registrar_name = nullable_htmlentities($row['registrar_name']);
$domain_webhost_name = nullable_htmlentities($row['webhost_name']);
$domain_dnshost_name = nullable_htmlentities($row['dnshost_name']);
$domain_mailhost_name = nullable_htmlentities($row['mailhost_name']);
$domain_created_at = nullable_htmlentities($row['domain_created_at']);
$domain_archived_at = nullable_htmlentities($row['domain_archived_at']);
$client_id = intval($row['domain_client_id']);
$client_name = nullable_htmlentities($row['client_name']);
// Add - if empty on the table
$domain_registrar_name_display = $domain_registrar_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_registrar_id'>
$domain_registrar_name
</a>" : "-";
$domain_webhost_name_display = $domain_webhost_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_webhost_id'>
$domain_webhost_name
</a>" : "-";
$domain_dnshost_name_display = $domain_dnshost_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_dnshost_id'>
$domain_dnshost_name
</a>" : "-";
$domain_mailhost_name_display = $domain_mailhost_name ? "
<a class='ajax-modal' href='#' data-modal-url='modals/vendor/vendor_details.php?id=$domain_mailhost_id'>
$domain_mailhost_name
</a>" : "-";
?>
<tr class="<?php echo $tr_class; ?>">
<td class="pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="domain_ids[]" value="<?php echo $domain_id ?>">
</div>
</td>
<td class="">
<a class="text-dark ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/domain/domain_edit.php?<?= $client_url ?>&id=<?= $domain_id ?>">
<div class="media">
<i class="fa fa-fw fa-2x fa-globe mr-3"></i>
<div class="media-body">
<div><?php echo $domain_name; ?></div>
<div><small class="text-secondary"><?php echo $domain_description; ?></small></div>
</div>
</div>
</a>
</td>
<td><?php echo $domain_registrar_name_display; ?></td>
<td><?php echo $domain_webhost_name_display; ?></td>
<td><?php echo $domain_dnshost_name_display; ?></td>
<td><?php echo $domain_mailhost_name_display; ?></td>
<td>
<div><?php echo $domain_expire ?: '-'; ?></div>
<?php if (!empty($domain_expire)) { ?>
<div><small><?php echo $domain_expire_ago; ?></small></div>
<?php } ?>
</td>
<?php if (!$client_url) { ?>
<td><a href="domains.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
<?php } ?>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/domain/domain_edit.php?<?= $client_url ?>&id=<?= $domain_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<?php if ($session_user_role == 3) { ?>
<?php if ($domain_archived_at) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-info confirm-link" href="post.php?unarchive_domain=<?php echo $domain_id; ?>">
<i class="fas fa-fw fa-redo mr-2"></i>Unarchive
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_domain=<?php echo $domain_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } else { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_domain=<?php echo $domain_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php } ?>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</form>
</div>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<script src="../js/bulk_actions.js"></script>
<?php require_once "../includes/footer.php";

View File

@@ -64,10 +64,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<h3 class="card-title mt-2"><i class="fas fa-fw fa-shopping-cart mr-2"></i>Expenses</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addExpenseModal"><i class="fas fa-plus mr-2"></i>New Expense</button>
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/expense/expense_add.php" data-modal-size="lg"><i class="fas fa-plus mr-2"></i>New Expense</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportExpensesModal">
<a class="dropdown-item text-dark ajax-modal" href="#"
data-modal-url="modals/expense/expense_export.php">
<i class="fa fa-fw fa-download mr-2"></i>Export
</a>
</div>
@@ -94,57 +95,45 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditCategoryModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/expense/expense_bulk_edit_category.php"
data-bulk="true">
<i class="fas fa-fw fa-list mr-2"></i>Set Category
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditAccountModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/expense/expense_bulk_edit_account.php"
data-bulk="true">
<i class="fas fa-fw fa-piggy-bank mr-2"></i>Set Account
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkEditClientModal">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/expense/expense_bulk_edit_client.php"
data-bulk="true">
<i class="fas fa-fw fa-user mr-2"></i>Set Client
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_expenses">
<a class="dropdown-item text-danger text-bold ajax-modal" href="#"
data-modal-url="modals/expense/expense_bulk_delete.php"
data-bulk="true">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
</a>
<?php } ?>
</div>
</div>
</div>
</div>
</div>
<div class="collapse mt-3 <?php if (isset($_GET['dtf']) || $_GET['canned_date'] !== "custom" || $account_filter || $vendor_filter || $category_filter) { echo "show"; } ?>" id="advancedFilter">
<div class="collapse mt-3 <?php if (isset($_GET['dtf']) && $_GET['dtf'] !== '1970-01-01' || $account_filter || $vendor_filter || $category_filter) { echo "show"; } ?>" id="advancedFilter">
<div class="row">
<div class="col-md-2">
<div class="col-md-3">
<div class="form-group">
<label>Canned Date</label>
<select onchange="this.form.submit()" class="form-control select2" name="canned_date">
<option <?php if ($_GET['canned_date'] == "custom") { echo "selected"; } ?> value="">Custom</option>
<option <?php if ($_GET['canned_date'] == "today") { echo "selected"; } ?> value="today">Today</option>
<option <?php if ($_GET['canned_date'] == "yesterday") { echo "selected"; } ?> value="yesterday">Yesterday</option>
<option <?php if ($_GET['canned_date'] == "thisweek") { echo "selected"; } ?> value="thisweek">This Week</option>
<option <?php if ($_GET['canned_date'] == "lastweek") { echo "selected"; } ?> value="lastweek">Last Week</option>
<option <?php if ($_GET['canned_date'] == "thismonth") { echo "selected"; } ?> value="thismonth">This Month</option>
<option <?php if ($_GET['canned_date'] == "lastmonth") { echo "selected"; } ?> value="lastmonth">Last Month</option>
<option <?php if ($_GET['canned_date'] == "thisyear") { echo "selected"; } ?> value="thisyear">This Year</option>
<option <?php if ($_GET['canned_date'] == "lastyear") { echo "selected"; } ?> value="lastyear">Last Year</option>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date From</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtf" max="2999-12-31" value="<?php echo nullable_htmlentities($dtf); ?>">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label>Date To</label>
<input onchange="this.form.submit()" type="date" class="form-control" name="dtt" max="2999-12-31" value="<?php echo nullable_htmlentities($dtt); ?>">
<label>Date range</label>
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
<input type="hidden" name="canned_date" id="canned_date" value="<?php echo nullable_htmlentities($_GET['canned_date']) ?? ''; ?>">
<input type="hidden" name="dtf" id="dtf" value="<?php echo nullable_htmlentities($dtf ?? ''); ?>">
<input type="hidden" name="dtt" id="dtt" value="<?php echo nullable_htmlentities($dtt ?? ''); ?>">
</div>
</div>
<div class="col-sm-2">
@@ -155,7 +144,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<?php
$sql_vendors_filter = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE EXISTS (SELECT 1 FROM expenses WHERE expense_vendor_id = vendor_id) ORDER BY vendor_name ASC");
while ($row = mysqli_fetch_array($sql_vendors_filter)) {
$vendor_id = intval($row['vendor_id']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
@@ -212,171 +201,161 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
</div>
</form>
<hr>
<form id="bulkActions" action="post.php" method="post" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=expense_date&order=<?php echo $disp; ?>">
Date <?php if ($sort == 'expense_date') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=category_name&order=<?php echo $disp; ?>">
Category <?php if ($sort == 'category_name') { echo $order_icon; } ?>
</a>
/
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=expense_description&order=<?php echo $disp; ?>">
Description <?php if ($sort == 'expense_description') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=vendor_name&order=<?php echo $disp; ?>">
Vendor <?php if ($sort == 'vendor_name') { echo $order_icon; } ?>
</a>
</th>
<th class="text-right">
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=expense_amount&order=<?php echo $disp; ?>">
Amount <?php if ($sort == 'expense_amount') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=account_name&order=<?php echo $disp; ?>">
Account <?php if ($sort == 'account_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'client_name') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover">
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=expense_date&order=<?php echo $disp; ?>">
Date <?php if ($sort == 'expense_date') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=category_name&order=<?php echo $disp; ?>">
Category <?php if ($sort == 'category_name') { echo $order_icon; } ?>
</a>
/
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=expense_description&order=<?php echo $disp; ?>">
Description <?php if ($sort == 'expense_description') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=vendor_name&order=<?php echo $disp; ?>">
Vendor <?php if ($sort == 'vendor_name') { echo $order_icon; } ?>
</a>
</th>
<th class="text-right">
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=expense_amount&order=<?php echo $disp; ?>">
Amount <?php if ($sort == 'expense_amount') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=account_name&order=<?php echo $disp; ?>">
Account <?php if ($sort == 'account_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">
Client <?php if ($sort == 'client_name') { echo $order_icon; } ?>
</a>
</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$expense_id = intval($row['expense_id']);
$expense_date = nullable_htmlentities($row['expense_date']);
$expense_amount = floatval($row['expense_amount']);
$expense_currency_code = nullable_htmlentities($row['expense_currency_code']);
$expense_description = nullable_htmlentities($row['expense_description']);
$expense_receipt = nullable_htmlentities($row['expense_receipt']);
$expense_reference = nullable_htmlentities($row['expense_reference']);
$expense_created_at = nullable_htmlentities($row['expense_created_at']);
$expense_vendor_id = intval($row['expense_vendor_id']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
$expense_category_id = intval($row['expense_category_id']);
$category_name = nullable_htmlentities($row['category_name']);
$account_name = nullable_htmlentities($row['account_name']);
$expense_account_id = intval($row['expense_account_id']);
$client_name = nullable_htmlentities($row['client_name']);
if(empty($client_name)) {
$client_name_display = "-";
} else {
$client_name_display = $client_name;
}
$expense_client_id = intval($row['expense_client_id']);
if (empty($expense_receipt)) {
$receipt_attached = "";
} else {
$path_info = pathinfo($expense_receipt);
$ext = $path_info['extension'];
$receipt_attached = "<a class='text-secondary mr-2' target='_blank' href='../uploads/expenses/$expense_receipt' download='$expense_date-$vendor_name-$category_name-$expense_id.$ext'><i class='fa fa-file'></i></a>";
}
?>
<tr>
<td class="pr-0 bg-light">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="expense_ids[]" value="<?php echo $expense_id ?>">
</div>
</td>
<td>
<?php echo $receipt_attached; ?>
<a class="text-dark ajax-modal" href="#" title="Created: <?php echo $expense_created_at; ?>"
data-modal-size="lg"
data-modal-url="modals/expense/expense_edit.php?id=<?= $expense_id ?>">
<?php echo $expense_date; ?>
</a>
</td>
<td>
<?php echo $category_name; ?>
<div class="text-secondary"><small><?php echo truncate($expense_description, 60); ?></small></div>
</td>
<td><?php echo $vendor_name; ?></td>
<td class="text-bold text-right"><?php echo numfmt_format_currency($currency_format, $expense_amount, $expense_currency_code); ?></td>
<td><?php echo $account_name; ?></td>
<td><?php echo $client_name_display; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<?php
if (!empty($expense_receipt)) { ?>
<a class="dropdown-item" href="<?php echo "../uploads/expenses/$expense_receipt"; ?>" download="<?php echo "$expense_date-$vendor_name-$category_name-$expense_id.pdf"; ?>">
<i class="fas fa-fw fa-download mr-2"></i>Download
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/expense/expense_edit.php?id=<?= $expense_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/expense/expense_copy.php?id=<?= $expense_id ?>">
<i class="fas fa-fw fa-copy mr-2"></i>Copy
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/expense/expense_refund.php?id=<?= $expense_id ?>">
<i class="fas fa-fw fa-undo-alt mr-2"></i>Refund
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_expense=<?php echo $expense_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
</div>
</div>
</td>
</tr>
<?php
while ($row = mysqli_fetch_array($sql)) {
$expense_id = intval($row['expense_id']);
$expense_date = nullable_htmlentities($row['expense_date']);
$expense_amount = floatval($row['expense_amount']);
$expense_currency_code = nullable_htmlentities($row['expense_currency_code']);
$expense_description = nullable_htmlentities($row['expense_description']);
$expense_receipt = nullable_htmlentities($row['expense_receipt']);
$expense_reference = nullable_htmlentities($row['expense_reference']);
$expense_created_at = nullable_htmlentities($row['expense_created_at']);
$expense_vendor_id = intval($row['expense_vendor_id']);
$vendor_name = nullable_htmlentities($row['vendor_name']);
$expense_category_id = intval($row['expense_category_id']);
$category_name = nullable_htmlentities($row['category_name']);
$account_name = nullable_htmlentities($row['account_name']);
$expense_account_id = intval($row['expense_account_id']);
$client_name = nullable_htmlentities($row['client_name']);
if(empty($client_name)) {
$client_name_display = "-";
} else {
$client_name_display = $client_name;
}
$expense_client_id = intval($row['expense_client_id']);
if (empty($expense_receipt)) {
$receipt_attached = "";
} else {
$path_info = pathinfo($expense_receipt);
$ext = $path_info['extension'];
$receipt_attached = "<a class='text-secondary mr-2' target='_blank' href='../uploads/expenses/$expense_receipt' download='$expense_date-$vendor_name-$category_name-$expense_id.$ext'><i class='fa fa-file'></i></a>";
}
?>
</tbody>
</table>
</div>
<?php require_once "modals/expense/expense_bulk_edit_category.php"; ?>
<?php require_once "modals/expense/expense_bulk_edit_account.php"; ?>
<?php require_once "modals/expense/expense_bulk_edit_client.php"; ?>
</form>
<?php require_once "../includes/filter_footer.php";
?>
<tr>
<td class="pr-0 bg-light">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="expense_ids[]" value="<?= $expense_id ?>">
</div>
</td>
<td>
<?php echo $receipt_attached; ?>
<a class="text-dark ajax-modal" href="#" title="Created: <?php echo $expense_created_at; ?>"
data-modal-size="lg"
data-modal-url="modals/expense/expense_edit.php?id=<?= $expense_id ?>">
<?php echo $expense_date; ?>
</a>
</td>
<td>
<?php echo $category_name; ?>
<div class="text-secondary"><small><?php echo truncate($expense_description, 60); ?></small></div>
</td>
<td><?php echo $vendor_name; ?></td>
<td class="text-bold text-right"><?php echo numfmt_format_currency($currency_format, $expense_amount, $expense_currency_code); ?></td>
<td><?php echo $account_name; ?></td>
<td><?php echo $client_name_display; ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<?php
if (!empty($expense_receipt)) { ?>
<a class="dropdown-item" href="<?php echo "../uploads/expenses/$expense_receipt"; ?>" download="<?php echo "$expense_date-$vendor_name-$category_name-$expense_id.pdf"; ?>">
<i class="fas fa-fw fa-download mr-2"></i>Download
</a>
<div class="dropdown-divider"></div>
<?php } ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/expense/expense_edit.php?id=<?= $expense_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Edit
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/expense/expense_copy.php?id=<?= $expense_id ?>">
<i class="fas fa-fw fa-copy mr-2"></i>Copy
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/expense/expense_refund.php?id=<?= $expense_id ?>">
<i class="fas fa-fw fa-undo-alt mr-2"></i>Refund
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_expense=<?php echo $expense_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
</div>
</div>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
<script src="../js/bulk_actions.js"></script>
<script src="/js/bulk_actions.js"></script>
<?php
require_once "modals/expense/expense_add.php";
require_once "modals/expense/expense_export.php";
require_once "../includes/footer.php";

File diff suppressed because it is too large Load Diff

622
agent/files_legacy.php Normal file
View File

@@ -0,0 +1,622 @@
<?php
// Default Column Sortby Filter
$sort = "file_name";
$order = "ASC";
require_once "includes/inc_all_client.php";
// Folder
if (!empty($_GET['folder_id'])) {
$folder_id = intval($_GET['folder_id']);
} else {
$folder_id = 0;
}
// Folder ID
$get_folder_id = 0;
if (!empty($_GET['folder_id'])) {
$get_folder_id = intval($_GET['folder_id']);
}
// View Mode -- 0 List, 1 Thumbnail
if (!empty($_GET['view'])) {
$view = intval($_GET['view']);
} else {
$view = 0;
}
if ($view == 1) {
$query_images = "AND (file_ext LIKE 'JPG' OR file_ext LIKE 'jpg' OR file_ext LIKE 'JPEG' OR file_ext LIKE 'jpeg' OR file_ext LIKE 'png' OR file_ext LIKE 'PNG' OR file_ext LIKE 'webp' OR file_ext LIKE 'WEBP')";
} else {
$query_images = '';
}
// Set Folder Location Var used when creating folders
$folder_location = 1;
if ($get_folder_id == 0 && isset($_GET["q"])) {
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM files
LEFT JOIN users ON file_created_by = user_id
WHERE file_client_id = $client_id
AND file_archived_at IS NULL
AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%')
$query_images
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}else{
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM files
LEFT JOIN users ON file_created_by = user_id
WHERE file_client_id = $client_id
AND file_folder_id = $folder_id
AND file_archived_at IS NULL
AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%')
$query_images
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$num_of_files = mysqli_num_rows($sql);
// Breadcrumbs
// Build the full folder path
$folder_id = $get_folder_id;
$folder_path = array();
while ($folder_id > 0) {
$sql_folder = mysqli_query($mysqli, "SELECT folder_name, parent_folder FROM folders WHERE folder_id = $folder_id");
if ($row_folder = mysqli_fetch_assoc($sql_folder)) {
$folder_name = nullable_htmlentities($row_folder['folder_name']);
$parent_folder = intval($row_folder['parent_folder']);
// Prepend the folder to the beginning of the array
array_unshift($folder_path, array('folder_id' => $folder_id, 'folder_name' => $folder_name));
// Move up to the parent folder
$folder_id = $parent_folder;
} else {
// If the folder is not found, break the loop
break;
}
}
?>
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-paperclip mr-2"></i>Files</h3>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/file/file_upload.php?client_id=<?= $client_id ?>&folder_id=<?= $get_folder_id ?>">
<i class="fas fa-fw fa-cloud-upload-alt mr-2"></i>Upload
</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item text-dark ajax-modal" href="#" data-modal-url="modals/folder/folder_add.php?client_id=<?= $client_id ?>&folder_location=1&current_folder_id=<?= $get_folder_id ?>">
<i class="fa fa-fw fa-folder-plus mr-2"></i>New Folder
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3 border-right mb-3">
<h4>Folders</h4>
<hr>
<ul class="nav nav-pills flex-column bg-light">
<li class="nav-item">
<a class="nav-link <?php if ($get_folder_id == 0) { echo "active"; } ?>" href="?client_id=<?php echo $client_id; ?>&folder_id=0">/</a>
</li>
<?php
// Function to check if a folder is an ancestor of the current folder
function is_ancestor_folder($folder_id, $current_folder_id, $client_id) {
global $mysqli;
// Base case: if current_folder_id is 0 or equal to folder_id
if ($current_folder_id == 0) {
return false;
}
if ($current_folder_id == $folder_id) {
return true;
}
// Get the parent folder of the current folder
$result = mysqli_query($mysqli, "SELECT parent_folder FROM folders WHERE folder_id = $current_folder_id AND folder_client_id = $client_id");
if ($row = mysqli_fetch_assoc($result)) {
$parent_folder_id = intval($row['parent_folder']);
// Recursive call to check the parent folder
return is_ancestor_folder($folder_id, $parent_folder_id, $client_id);
} else {
// Folder not found
return false;
}
}
// Recursive function to display folders and subfolders
function display_folders($parent_folder_id, $client_id, $indent = 0) {
global $mysqli, $get_folder_id, $session_user_role;
$sql_folders = mysqli_query($mysqli, "SELECT * FROM folders WHERE parent_folder = $parent_folder_id AND folder_location = 1 AND folder_client_id = $client_id ORDER BY folder_name ASC");
while ($row = mysqli_fetch_array($sql_folders)) {
$folder_id = intval($row['folder_id']);
$folder_name = nullable_htmlentities($row['folder_name']);
// Get the number of files in the folder
$row2 = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('file_id') AS num FROM files WHERE file_folder_id = $folder_id AND file_archived_at IS NULL"));
$num_files = intval($row2['num']);
// Get the number of subfolders
$subfolder_result = mysqli_query($mysqli, "SELECT COUNT(*) AS count FROM folders WHERE parent_folder = $folder_id AND folder_client_id = $client_id");
$subfolder_count = intval(mysqli_fetch_assoc($subfolder_result)['count']);
echo '<li class="nav-item">';
echo '<div class="row">';
echo '<div class="col-10">';
echo '<a class="nav-link ';
if ($get_folder_id == $folder_id) { echo "active"; }
echo '" href="?client_id=' . $client_id . '&folder_id=' . $folder_id . '">';
// Indentation for subfolders
echo str_repeat('&nbsp;', $indent * 4);
// Determine if the folder is open
if ($get_folder_id == $folder_id || is_ancestor_folder($folder_id, $get_folder_id, $client_id)) {
echo '<i class="fas fa-fw fa-folder-open"></i>';
} else {
echo '<i class="fas fa-fw fa-folder"></i>';
}
echo ' ' . $folder_name;
if ($num_files > 0) {
echo "<span class='badge badge-pill badge-dark float-right mt-1'>$num_files</span>";
}
echo '</a>';
echo '</div>';
echo '<div class="col-2">';
?>
<div class="dropdown">
<button class="btn btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/folder/folder_rename.php?id=<?= $folder_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<?php
// Only show delete option if user is admin, folder has no files, and no subfolders
if ($session_user_role == 3 && $num_files == 0 && $subfolder_count == 0) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?delete_folder=<?php echo $folder_id; ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
<?php
echo '</div>';
echo '</div>';
if ($subfolder_count > 0) {
// Display subfolders
echo '<ul class="nav nav-pills flex-column bg-light">';
display_folders($folder_id, $client_id, $indent + 1);
echo '</ul>';
}
echo '</li>';
}
}
// Start displaying folders from the root (parent_folder = 0)
display_folders(0, $client_id);
?>
</ul>
<?php //require_once "modals/folder/folder_add.php"; ?>
</div>
<div class="col-md-9">
<form autocomplete="off">
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<input type="hidden" name="view" value="<?php echo $view; ?>">
<input type="hidden" name="folder_id" value="<?php echo $get_folder_id; ?>">
<div class="row">
<div class="col-md-5">
<div class="input-group mb-3 mb-md-0">
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search for files in <?php if($get_folder_id == 0) { echo "all folders"; } else { echo "current folder"; } ?>">
<div class="input-group-append">
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
</div>
</div>
</div>
<div class="col-md-7">
<div class="btn-group float-right">
<a href="?<?php echo $url_query_strings_sort; ?>&view=0" class="btn <?php if($view == 0){ echo "btn-primary"; } else { echo "btn-outline-secondary"; } ?>"><i class="fas fa-list-ul"></i></a>
<a href="?<?php echo $url_query_strings_sort; ?>&view=1" class="btn <?php if($view == 1){ echo "btn-primary"; } else { echo "btn-outline-secondary"; } ?>"><i class="fas fa-th-large"></i></a>
<div class="dropdown ml-2" id="bulkActionButton" hidden>
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
</button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_bulk_move.php?client_id=<?= $client_id ?>"
data-bulk="true">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger text-bold"
type="submit" form="bulkActions" name="bulk_delete_files">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</button>
</div>
</div>
</div>
</div>
</div>
</form>
<nav class="mt-3">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="?client_id=<?php echo $client_id; ?>&folder_id=0">
<i class="fas fa-fw fa-folder mr-2"></i>Root
</a>
</li>
<?php
// Output breadcrumb items for each folder in the path
foreach ($folder_path as $folder) {
$bread_crumb_folder_id = $folder['folder_id']; // Already Sanitized before it was pushed into array
$bread_crumb_folder_name = $folder['folder_name']; // Already Sanitized before it was pushed into array
?>
<li class="breadcrumb-item">
<a href="?client_id=<?php echo $client_id; ?>&folder_id=<?php echo $bread_crumb_folder_id; ?>">
<i class="fas fa-fw fa-folder-open mr-2"></i><?php echo $bread_crumb_folder_name; ?>
</a>
</li>
<?php
}
?>
</ol>
</nav>
<hr>
<?php
if($view == 1){
?>
<div class="row">
<?php
$files = [];
while ($row = mysqli_fetch_array($sql)) {
$file_id = intval($row['file_id']);
$file_name = nullable_htmlentities($row['file_name']);
$file_reference_name = nullable_htmlentities($row['file_reference_name']);
$file_ext = nullable_htmlentities($row['file_ext']);
$file_size = intval($row['file_size']);
$file_size_KB = number_format($file_size / 1024);
$file_mime_type = nullable_htmlentities($row['file_mime_type']);
$file_uploaded_by = nullable_htmlentities($row['user_name']);
// Store file data into an array for JS
$files[] = [
'id' => $file_id,
'name' => $file_name,
'preview' => "../uploads/clients/$client_id/$file_reference_name"
];
?>
<div class="col-xl-2 col-lg-2 col-md-6 col-sm-6 mb-3 text-center">
<a href="#" onclick="openModal(<?php echo count($files)-1; ?>)"><!-- passing the index -->
<img class="img-thumbnail" src="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" alt="<?php echo $file_reference_name ?>">
</a>
<div>
<div class="dropdown float-right">
<button class="btn btn-link btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" download="<?php echo $file_name; ?>">
<i class="fas fa-fw fa-cloud-download-alt mr-2"></i>Download
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#shareModal" onclick="populateShareModal(<?php echo "$client_id, 'File', $file_id"; ?>)">
<i class="fas fa-fw fa-share mr-2"></i>Share
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_rename.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_move.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#linkAssetToFileModal<?php echo $file_id; ?>">
<i class="fas fa-fw fa-desktop mr-2"></i>Asset
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_file=<?php echo $file_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
<small class="text-secondary"><?php echo $file_name; ?></small>
</div>
</div>
<?php
require "modals/file/file_view.php";
}
?>
<script>
// Pass PHP array to JavaScript
var files = <?php echo json_encode($files); ?>;
var currentIndex = 0; // Keep track of which file is displayed
</script>
</div>
<?php } else { ?>
<form id="bulkActions" action="post.php" method="post">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="table-responsive-sm">
<table class="table border">
<thead class="thead-light <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input" id="selectAllCheckbox" type="checkbox" onclick="checkAll(this)">
</div>
</td>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_name&order=<?php echo $disp; ?>">
Name <?php if ($sort == 'file_name') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_mime_type&order=<?php echo $disp; ?>">
Type <?php if ($sort == 'file_mime_type') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_size&order=<?php echo $disp; ?>">
Size <?php if ($sort == 'file_size') { echo $order_icon; } ?>
</a>
</th>
<th>
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_created_at&order=<?php echo $disp; ?>">
Uploaded <?php if ($sort == 'file_created_at') { echo $order_icon; } ?>
</a>
</th>
<th></th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql)) {
$file_id = intval($row['file_id']);
$file_name = nullable_htmlentities($row['file_name']);
$file_description = nullable_htmlentities($row['file_description']);
$file_reference_name = nullable_htmlentities($row['file_reference_name']);
$file_ext = nullable_htmlentities($row['file_ext']);
if ($file_ext == 'pdf') {
$file_icon = "file-pdf";
} elseif ($file_ext == 'gz' || $file_ext == 'tar' || $file_ext == 'zip' || $file_ext == '7z' || $file_ext == 'rar') {
$file_icon = "file-archive";
} elseif ($file_ext == 'txt' || $file_ext == 'md') {
$file_icon = "file-alt";
} elseif ($file_ext == 'msg') {
$file_icon = "envelope";
} elseif ($file_ext == 'doc' || $file_ext == 'docx' || $file_ext == 'odt') {
$file_icon = "file-word";
} elseif ($file_ext == 'xls' || $file_ext == 'xlsx' || $file_ext == 'ods') {
$file_icon = "file-excel";
} elseif ($file_ext == 'pptx' || $file_ext == 'odp') {
$file_icon = "file-powerpoint";
} elseif ($file_ext == 'mp3' || $file_ext == 'wav' || $file_ext == 'ogg') {
$file_icon = "file-audio";
} elseif ($file_ext == 'mov' || $file_ext == 'mp4' || $file_ext == 'av1') {
$file_icon = "file-video";
} elseif ($file_ext == 'jpg' || $file_ext == 'jpeg' || $file_ext == 'png' || $file_ext == 'gif' || $file_ext == 'webp' || $file_ext == 'bmp' || $file_ext == 'tif') {
$file_icon = "file-image";
} else {
$file_icon = "file";
}
$file_size = intval($row['file_size']);
$file_size_KB = number_format($file_size / 1024);
$file_mime_type = nullable_htmlentities($row['file_mime_type']);
$file_size = intval($row['file_size']);
$file_uploaded_by = nullable_htmlentities($row['user_name']);
$file_created_at = nullable_htmlentities($row['file_created_at']);
$file_folder_id = intval($row['file_folder_id']);
// Check if shared
$sql_shared = mysqli_query(
$mysqli,
"SELECT * FROM shared_items
WHERE item_client_id = $client_id
AND item_active = 1
AND item_views != item_view_limit
AND item_expire_at > NOW()
AND item_type = 'File'
AND item_related_id = $file_id
LIMIT 1"
);
$file_shared = (mysqli_num_rows($sql_shared) > 0) ? true : false;
if ($file_shared) {
$row = mysqli_fetch_array($sql_shared);
$item_id = intval($row['item_id']);
$item_active = nullable_htmlentities($row['item_active']);
$item_key = nullable_htmlentities($row['item_key']);
$item_type = nullable_htmlentities($row['item_type']);
$item_related_id = intval($row['item_related_id']);
$item_note = nullable_htmlentities($row['item_note']);
$item_recipient = nullable_htmlentities($row['item_recipient']);
$item_views = nullable_htmlentities($row['item_views']);
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
$item_created_at = nullable_htmlentities($row['item_created_at']);
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
$item_expire_at_human = timeAgo($row['item_expire_at']);
}
?>
<tr>
<td class="bg-light pr-0">
<div class="form-check">
<input class="form-check-input bulk-select" type="checkbox" name="file_ids[]" value="<?php echo $file_id ?>">
</div>
</td>
<td>
<a href="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" target="_blank">
<div class="media">
<i class="fa fa-fw fa-2x fa-<?php echo $file_icon; ?> text-dark mr-3"></i>
<div class="media-body">
<p>
<?php echo basename($file_name); ?>
<br>
<small class="text-secondary"><?php echo $file_description; ?></small>
</p>
</div>
</div>
</a>
</td>
<td><?php echo $file_mime_type; ?></td>
<td><?php echo $file_size_KB; ?> KB</td>
<td>
<?php echo $file_created_at; ?>
<div class="text-secondary mt-1"><?php echo $file_uploaded_by; ?></div>
</td>
<td>
<?php if ($file_shared) { ?>
<div class="media" title="Expires <?php echo $item_expire_at_human; ?>">
<i class="fas fa-link mr-2 mt-1"></i>
<div class="media-body">Shared
<br>
<small class="text-secondary"><?php echo $item_recipient; ?></small>
</div>
</div>
<?php } ?>
</td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
<i class="fas fa-ellipsis-h"></i>
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="<?php echo "../uploads/clients/$client_id/$file_reference_name"; ?>" download="<?php echo $file_name; ?>">
<i class="fas fa-fw fa-cloud-download-alt mr-2"></i>Download
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#shareModal" onclick="populateShareModal(<?php echo "$client_id, 'File', $file_id"; ?>)">
<i class="fas fa-fw fa-share mr-2"></i>Share
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_rename.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-edit mr-2"></i>Rename
</a>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/file/file_move.php?id=<?= $file_id ?>">
<i class="fas fa-fw fa-exchange-alt mr-2"></i>Move
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#linkAssetToFileModal<?php echo $file_id; ?>">
<i class="fas fa-fw fa-desktop mr-2"></i>Asset
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_file=<?php echo $file_id; ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
</div>
</div>
</td>
</tr>
<?php
require "modals/file/file_link_asset.php";
}
?>
</tbody>
</table>
</div>
</form>
<?php } ?>
<?php require_once "../includes/filter_footer.php"; ?>
</div>
</div>
</div>
</div>
<script>
function openModal(index) {
currentIndex = index;
updateModalContent();
$('#viewFileModal').modal('show');
}
function updateModalContent() {
document.getElementById('modalTitle').innerText = files[currentIndex].name;
document.getElementById('modalImage').src = files[currentIndex].preview;
}
function nextFile() {
currentIndex = (currentIndex + 1) % files.length; // loop around
updateModalContent();
}
function prevFile() {
currentIndex = (currentIndex - 1 + files.length) % files.length; // loop around
updateModalContent();
}
</script>
<script src="../js/bulk_actions.js"></script>
<?php
require_once "modals/share_modal.php";
require_once "modals/file/file_delete.php";
require_once "../includes/footer.php";

View File

@@ -85,6 +85,8 @@ if (isset($_GET['query'])) {
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
WHERE ticket_archived_at IS NULL
AND (ticket_subject LIKE '%$query%'
OR ticket_details LIKE '%$query%'
OR CONCAT(ticket_prefix,ticket_number) LIKE '%$query%'
OR ticket_number = '$ticket_num_query')
$access_permission_query
ORDER BY ticket_id DESC LIMIT 5"
@@ -107,11 +109,20 @@ if (isset($_GET['query'])) {
ORDER BY credential_id DESC LIMIT 5"
);
$sql_quotes = mysqli_query($mysqli, "SELECT * FROM quotes
LEFT JOIN clients ON quote_client_id = client_id
LEFT JOIN categories ON quote_category_id = category_id
WHERE quote_archived_at IS NULL
AND (CONCAT(quote_prefix,quote_number) LIKE '%$query%' OR quote_number LIKE '%$query%' OR quote_scope LIKE '%$query%')
$access_permission_query
ORDER BY quote_number DESC LIMIT 5"
);
$sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices
LEFT JOIN clients ON invoice_client_id = client_id
LEFT JOIN categories ON invoice_category_id = category_id
WHERE invoice_archived_at IS NULL
AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$query%' OR invoice_scope LIKE '%$query%')
AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$query%' OR invoice_number LIKE '%$query%' OR invoice_scope LIKE '%$query%')
$access_permission_query
ORDER BY invoice_number DESC LIMIT 5"
);
@@ -507,10 +518,10 @@ if (isset($_GET['query'])) {
?>
<tr>
<td><a href="ticket.php?ticket_id=<?php echo $ticket_id ?>"><?php echo $ticket_prefix . $ticket_number; ?></a></td>
<td><?php echo $ticket_subject; ?></td>
<td><?php echo $ticket_status_name; ?></td>
<td><a href="tickets.php?client_id=<?php echo $client_id ?>"><?php echo $client_name; ?></a></td>
<td><a href="ticket.php?client_id=<?= $client_id ?>&ticket_id=<?= $ticket_id ?>"><?= $ticket_prefix . $ticket_number ?></a></td>
<td><?= $ticket_subject ?></td>
<td><?= $ticket_status_name ?></td>
<td><a href="tickets.php?client_id=<?= $client_id ?>"><?= $client_name ?></a></td>
</tr>
<?php } ?>
@@ -626,6 +637,57 @@ if (isset($_GET['query'])) {
<?php } ?>
<?php if (mysqli_num_rows($sql_quotes) > 0) { ?>
<!-- Contacts-->
<div class="col-sm-6">
<div class="card card-dark mb-3">
<div class="card-header">
<h6 class="card-title"><i class="fas fa-fw fa-file-invoice mr-2"></i>Quotes</h6>
</div>
<div class="card-body">
<table class="table table-striped table-borderless">
<thead>
<tr>
<th>Number</th>
<th>Status</th>
<th>Amount</th>
<th>Client</th>
</tr>
</thead>
<tbody>
<?php
while ($row = mysqli_fetch_array($sql_quotes)) {
$quote_id = intval($row['quote_id']);
$quote_prefix = nullable_htmlentities($row['quote_prefix']);
$quote_number = intval($row['quote_number']);
$quote_amount = floatval($row['quote_amount']);
$quote_currency_code = nullable_htmlentities($row['quote_currency_code']);
$quote_status = nullable_htmlentities($row['quote_status']);
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<tr>
<td><a href="quote.php?client_id=<?= $client_id ?>&quote_id=<?php echo $quote_id; ?>"><?php echo "$quote_prefix$quote_number"; ?></a></td>
<td><?php echo $quote_status; ?></td>
<td><?php echo numfmt_format_currency($currency_format, $quote_amount, $quote_currency_code); ?></td>
<td><a href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
</div>
</div>
<?php } ?>
<?php if (mysqli_num_rows($sql_invoices) > 0) { ?>
<!-- Contacts-->
@@ -660,7 +722,7 @@ if (isset($_GET['query'])) {
?>
<tr>
<td><a href="invoice.php?invoice_id=<?php echo $invoice_id; ?>"><?php echo "$invoice_prefix$invoice_number"; ?></a></td>
<td><a href="invoice.php?client_id=<?= $client_id ?>&invoice_id=<?php echo $invoice_id; ?>"><?php echo "$invoice_prefix$invoice_number"; ?></a></td>
<td><?php echo $invoice_status; ?></td>
<td><?php echo numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code); ?></td>
<td><a href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a></td>
@@ -805,7 +867,7 @@ if (isset($_GET['query'])) {
<?php echo "$client_name - $ticket_prefix$ticket_number - $ticket_subject"; ?>
</h3>
<div class="card-tools">
<a href="ticket.php?ticket_id=<?php echo $ticket_id; ?>" target="_blank">Open <i class="fa fa-fw fa-external-link-alt"></i></a>
<a href="ticket.php?client_id=<?= $client_id ?>&ticket_id=<?= $ticket_id ?>" target="_blank">Open <i class="fa fa-fw fa-external-link-alt"></i></a>
</div>
</div>
<div class="card-body prettyContent">

View File

@@ -53,6 +53,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-address-book"></i>
<p>
Contacts
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/contact/contact_add.php"></span>
<?php
if ($num_contacts > 0) { ?>
<span class="right badge text-light"><?php echo $num_contacts; ?></span>
@@ -65,6 +66,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-map-marker-alt"></i>
<p>
Locations
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/location/location_add.php"></span>
<?php
if ($num_locations > 0) { ?>
<span class="right badge text-light"><?php echo $num_locations; ?></span>
@@ -77,6 +79,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-desktop"></i>
<p>
Assets
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/asset/asset_add.php"></span>
<?php
if ($num_assets > 0) { ?>
<span class="right badge text-light"><?php echo $num_assets; ?></span>
@@ -89,6 +92,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-cube"></i>
<p>
Licenses
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/software/software_add.php"></span>
<?php
if ($num_software > 0) { ?>
<span class="right badge text-light"><?php echo $num_software; ?></span>
@@ -101,6 +105,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-key"></i>
<p>
Credentials
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/credential/credential_add.php"></span>
<?php
if ($num_credentials > 0) { ?>
<span class="right badge text-light"><?php echo $num_credentials; ?></span>
@@ -113,6 +118,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-network-wired"></i>
<p>
Networks
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/network/network_add.php"></span>
<?php
if ($num_networks > 0) { ?>
<span class="right badge text-light"><?php echo $num_networks; ?></span>
@@ -125,6 +131,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-lock"></i>
<p>
Certificates
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/certificate/certificate_add.php"></span>
<?php
if ($num_certificates > 0) { ?>
<span class="right badge text-light"><?php echo $num_certificates; ?></span>
@@ -137,6 +144,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-globe"></i>
<p>
Domains
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/domain/domain_add.php"></span>
<?php
if ($num_domains > 0) { ?>
<span class="right badge text-light"><?php echo $num_domains; ?></span>
@@ -149,6 +157,7 @@ $num_software = $row['num'];
<i class="nav-icon fas fa-stream"></i>
<p>
Services
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/agent/modals/service/service_add.php"></span>
<?php
if ($num_services > 0) { ?>
<span class="right badge text-light"><?php echo $num_services; ?></span>

View File

@@ -1,7 +1,7 @@
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-<?php if (isset($_GET['client_id'])) { echo "gray"; } else { echo nullable_htmlentities($config_theme); } ?> d-print-none">
<a class="brand-link pb-1 mt-1" href="clients.php">
<a class="brand-link pb-1 mt-1" href="/agent/clients.php">
<p class="h5">
<i class="nav-icon fas fa-arrow-left ml-3 mr-2"></i>
<span class="brand-text">
@@ -19,14 +19,14 @@
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
<li class="nav-item mt-3">
<a href="client_overview.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_overview.php") { echo "active"; } ?>">
<a href="/agent/client_overview.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_overview.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-tachometer-alt"></i>
<p>Overview</p>
</a>
</li>
<li class="nav-item">
<a href="contacts.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "contacts.php" || basename($_SERVER["PHP_SELF"]) == "contact_details.php") { echo "active"; } ?>">
<a href="/agent/contacts.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "contacts.php" || basename($_SERVER["PHP_SELF"]) == "contact_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-address-book"></i>
<p>
Contacts
@@ -39,7 +39,7 @@
</li>
<li class="nav-item">
<a href="locations.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "locations.php") { echo "active"; } ?>">
<a href="/agent/locations.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "locations.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-map-marker-alt"></i>
<p>
Locations
@@ -55,7 +55,7 @@
<li class="nav-header mt-3">SUPPORT</li>
<li class="nav-item">
<a href="tickets.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "tickets.php" || basename($_SERVER["PHP_SELF"]) == "ticket.php") { echo "active"; } ?>">
<a href="/agent/tickets.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "tickets.php" || basename($_SERVER["PHP_SELF"]) == "ticket.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>
Tickets
@@ -69,7 +69,7 @@
</li>
<li class="nav-item">
<a href="recurring_tickets.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_tickets.php") { echo "active"; } ?>">
<a href="/agent/recurring_tickets.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_tickets.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-redo-alt"></i>
<p>
Recurring Tickets
@@ -83,7 +83,7 @@
</li>
<li class="nav-item">
<a href="projects.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "projects.php" || basename($_SERVER["PHP_SELF"]) == "project_details.php") { echo "active"; } ?>">
<a href="/agent/projects.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "projects.php" || basename($_SERVER["PHP_SELF"]) == "project_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>
Projects
@@ -97,7 +97,7 @@
<?php } ?>
<li class="nav-item">
<a href="vendors.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "vendors.php") { echo "active"; } ?>">
<a href="/agent/vendors.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "vendors.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-building"></i>
<p>
Vendors
@@ -110,7 +110,7 @@
</li>
<li class="nav-item">
<a href="calendar.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "calendar.php") { echo "active"; } ?>">
<a href="/agent/calendar.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "calendar.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-calendar-alt"></i>
<p>
Calendar
@@ -128,7 +128,7 @@
<?php if (lookupUserPermission("module_support") >= 1) { ?>
<li class="nav-item">
<a href="assets.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "assets.php" || basename($_SERVER["PHP_SELF"]) == "client_asset_details.php") { echo "active"; } ?>">
<a href="/agent/assets.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "assets.php" || basename($_SERVER["PHP_SELF"]) == "client_asset_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-desktop"></i>
<p>
Assets
@@ -141,7 +141,7 @@
</li>
<li class="nav-item">
<a href="software.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "software.php") { echo "active"; } ?>">
<a href="/agent/software.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "software.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-cube"></i>
<p>
Licenses
@@ -155,7 +155,7 @@
<?php if (lookupUserPermission("module_credential") >= 1) { ?>
<li class="nav-item">
<a href="credentials.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "credentials.php") { echo "active"; } ?>">
<a href="/agent/credentials.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "credentials.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-key"></i>
<p>
Credentials
@@ -169,7 +169,7 @@
<?php } ?>
<li class="nav-item">
<a href="networks.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "networks.php") { echo "active"; } ?>">
<a href="/agent/networks.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "networks.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-network-wired"></i>
<p>
Networks
@@ -182,7 +182,7 @@
</li>
<li class="nav-item">
<a href="racks.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "racks.php") { echo "active"; } ?>">
<a href="/agent/racks.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "racks.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-server"></i>
<p>
Racks
@@ -195,11 +195,10 @@
</li>
<li class="nav-item">
<a href="certificates.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "certificates.php") { echo "active"; } ?>">
<a href="/agent/certificates.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "certificates.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-lock"></i>
<p>
Certificates
<?php
if ($num_certificates > 0) { ?>
<span class="right badge <?php if ($num_certificates_expiring > 0) { ?> badge-warning text-dark <?php } ?> <?php if ($num_certificates_expired > 0) { ?> badge-danger <?php } ?> text-white"><?php echo $num_certificates; ?></span>
@@ -209,11 +208,10 @@
</li>
<li class="nav-item">
<a href="domains.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "domains.php") { echo "active"; } ?>">
<a href="/agent/domains.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "domains.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-globe"></i>
<p>
Domains
<?php
if ($num_domains > 0) { ?>
<span class="right badge <?php if (isset($num_domains_expiring)) { ?> badge-warning text-dark<?php } ?> <?php if (isset($num_domains_expired)) { ?> badge-danger <?php } ?> text-white"><?php echo $num_domains; ?></span>
@@ -223,7 +221,7 @@
</li>
<li class="nav-item">
<a href="services.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "services.php") { echo "active"; } ?>">
<a href="/agent/services.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "services.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-stream"></i>
<p>
Services
@@ -235,25 +233,12 @@
</a>
</li>
<li class="nav-item">
<a href="documents.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "documents.php" || basename($_SERVER["PHP_SELF"]) == "document_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-folder"></i>
<p>
Documents
<?php
if ($num_documents > 0) { ?>
<span class="right badge text-light"><?php echo $num_documents; ?></span>
<?php } ?>
</p>
</a>
</li>
<?php } ?>
<!-- Allow files even without module_support for things like contracts, etc. ) -->
<li class="nav-item">
<a href="files.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "files.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-paperclip"></i>
<a href="/agent/files.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "files.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-folder"></i>
<p>
Files
<?php
@@ -273,7 +258,7 @@
<?php if (lookupUserPermission("module_sales") >= 1) { ?>
<li class="nav-item">
<a href="invoices.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "invoices.php" || basename($_SERVER["PHP_SELF"]) == "invoice.php") { echo "active"; } ?>">
<a href="/agent/invoices.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "invoices.php" || basename($_SERVER["PHP_SELF"]) == "invoice.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-file-invoice"></i>
<p>
Invoices
@@ -286,7 +271,7 @@
</li>
<li class="nav-item">
<a href="recurring_invoices.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_invoices.php" || basename($_SERVER["PHP_SELF"]) == "recurring_invoice.php") { echo "active"; } ?>">
<a href="/agent/recurring_invoices.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_invoices.php" || basename($_SERVER["PHP_SELF"]) == "recurring_invoice.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-redo-alt"></i>
<p>
Recurring Invoices
@@ -299,7 +284,7 @@
</li>
<li class="nav-item">
<a href="quotes.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "quotes.php" || basename($_SERVER["PHP_SELF"]) == "quote.php") { echo "active"; } ?>">
<a href="/agent/quotes.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "quotes.php" || basename($_SERVER["PHP_SELF"]) == "quote.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-comment-dollar"></i>
<p>
Quotes
@@ -315,7 +300,7 @@
<?php if (lookupUserPermission("module_financial") >= 1) { ?>
<li class="nav-item">
<a href="payments.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "payments.php") { echo "active"; } ?>">
<a href="/agent/payments.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "payments.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-credit-card"></i>
<p>
Payments
@@ -329,7 +314,7 @@
<?php } ?>
<li class="nav-item">
<a href="trips.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "trips.php") { echo "active"; } ?>">
<a href="/agent/trips.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "trips.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-route"></i>
<p>
Trips

View File

@@ -29,15 +29,16 @@ if (isset($_GET['client_id'])) {
$sql = mysqli_query(
$mysqli,
"SELECT * FROM clients
LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1
LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1
LEFT JOIN locations ON client_id = location_client_id AND location_primary = 1
LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
WHERE client_id = $client_id"
);
if (mysqli_num_rows($sql) == 0) {
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/header.php';
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1></center>";
echo "<center><h1 class='text-secondary mt-5'>Nothing to see here</h1><a class='btn btn-lg btn-secondary mt-3' href='javascript:history.back()'><i class='fa fa-fw fa-arrow-left'></i> Go Back</a></center>";
exit;
} else {
$row = mysqli_fetch_array($sql);

View File

@@ -1,7 +1,7 @@
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-<?php echo nullable_htmlentities($config_theme); ?> d-print-none">
<a class="brand-link" href="dashboard.php">
<a class="brand-link" href="/agent/dashboard.php">
<div class="brand-image"></div>
<span class="brand-text h4"><?php echo nullable_htmlentities($session_company_name); ?></span>
</a>
@@ -13,20 +13,20 @@
<nav>
<ul class="nav nav-pills nav-sidebar flex-column mt-3" data-widget="treeview" data-accordion="false">
<li class="nav-item">
<a href="dashboard.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "dashboard.php") { echo "active"; } ?>">
<a href="/agent/dashboard.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "dashboard.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-tachometer-alt"></i>
<p>Dashboard</p>
</a>
</li>
<?php if (lookupUserPermission("module_client") >= 1) { ?>
<li class="nav-item">
<a href="clients.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients.php") { echo "active"; } ?>">
<a href="/agent/clients.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-users"></i>
<p>
Clients
<?php if ($num_active_clients) { ?>
<span class="right badge text-light" data-toggle="tooltip" title="Active Clients"><?php echo $num_active_clients; ?></span>
<?php } ?>
Clients
<?php if ($num_active_clients) { ?>
<span class="right badge text-light" data-toggle="tooltip" title="Active Clients"><?php echo $num_active_clients; ?></span>
<?php } ?>
</p>
</a>
</li>
@@ -36,7 +36,7 @@
<?php if ($config_module_enable_ticketing == 1) { ?>
<li class="nav-header mt-3">SUPPORT</li>
<li class="nav-item">
<a href="tickets.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "tickets.php" || basename($_SERVER["PHP_SELF"]) == "ticket.php") { echo "active"; } ?>">
<a href="/agent/tickets.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "tickets.php" || basename($_SERVER["PHP_SELF"]) == "ticket.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>
Tickets
@@ -47,7 +47,7 @@
</a>
</li>
<li class="nav-item">
<a href="recurring_tickets.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_tickets.php") { echo "active"; } ?>">
<a href="/agent/recurring_tickets.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_tickets.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-redo-alt"></i>
<p>
Recurring Tickets
@@ -58,7 +58,7 @@
</a>
</li>
<li class="nav-item">
<a href="projects.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "projects.php" || basename($_SERVER["PHP_SELF"]) == "project_details.php") { echo "active"; } ?>">
<a href="/agent/projects.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "projects.php" || basename($_SERVER["PHP_SELF"]) == "project_details.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>
Projects
@@ -72,7 +72,7 @@
<?php } ?>
<li class="nav-item">
<a href="calendar.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "calendar.php") { echo "active"; } ?>">
<a href="/agent/calendar.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "calendar.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-calendar-alt"></i>
<p>Calendar</p>
</a>
@@ -80,7 +80,7 @@
<?php if ($config_module_enable_accounting == 1 && lookupUserPermission("module_sales") >= 1) { ?>
<li class="nav-header mt-3">BILLING</li>
<li class="nav-item">
<a href="quotes.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "quotes.php" || basename($_SERVER["PHP_SELF"]) == "quote.php") { echo "active"; } ?>">
<a href="/agent/quotes.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "quotes.php" || basename($_SERVER["PHP_SELF"]) == "quote.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-comment-dollar"></i>
<p>
Quotes
@@ -91,7 +91,7 @@
</a>
</li>
<li class="nav-item">
<a href="invoices.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "invoices.php" || basename($_SERVER["PHP_SELF"]) == "invoice.php") { echo "active"; } ?>">
<a href="/agent/invoices.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "invoices.php" || basename($_SERVER["PHP_SELF"]) == "invoice.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-file-invoice"></i>
<p>
Invoices
@@ -102,7 +102,7 @@
</a>
</li>
<li class="nav-item">
<a href="recurring_invoices.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_invoices.php" || basename($_SERVER["PHP_SELF"]) == "recurring_invoice.php") { echo "active"; } ?>">
<a href="/agent/recurring_invoices.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_invoices.php" || basename($_SERVER["PHP_SELF"]) == "recurring_invoice.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-redo-alt"></i>
<p>
Recurring Invoices
@@ -113,13 +113,13 @@
</a>
</li>
<li class="nav-item">
<a href="revenues.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "revenues.php") { echo "active"; } ?>">
<a href="/agent/revenues.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "revenues.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-hand-holding-usd"></i>
<p>Revenues</p>
</a>
</li>
<li class="nav-item">
<a href="products.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "products.php") { echo "active"; } ?>">
<a href="/agent/products.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "products.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-box-open"></i>
<p>Products</p>
</a>
@@ -128,25 +128,25 @@
<?php if ($config_module_enable_accounting == 1 && lookupUserPermission("module_financial") >= 1) { ?>
<li class="nav-header mt-3">FINANCE</li>
<li class="nav-item">
<a href="payments.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "payments.php") { echo "active"; } ?>">
<a href="/agent/payments.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "payments.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-credit-card"></i>
<p>Payments</p>
</a>
</li>
<li class="nav-item">
<a href="vendors.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "vendors.php") { echo "active"; } ?>">
<a href="/agent/vendors.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "vendors.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-building"></i>
<p>Vendors</p>
</a>
</li>
<li class="nav-item">
<a href="expenses.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "expenses.php") { echo "active"; } ?>">
<a href="/agent/expenses.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "expenses.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-shopping-cart"></i>
<p>Expenses</p>
</a>
</li>
<li class="nav-item">
<a href="recurring_expenses.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_expenses.php") { echo "active"; } ?>">
<a href="/agent/recurring_expenses.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "recurring_expenses.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-redo-alt"></i>
<p>
Recurring Expenses
@@ -157,19 +157,19 @@
</a>
</li>
<li class="nav-item">
<a href="accounts.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "accounts.php") { echo "active"; } ?>">
<a href="/agent/accounts.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "accounts.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-piggy-bank"></i>
<p>Accounts</p>
</a>
</li>
<li class="nav-item">
<a href="transfers.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "transfers.php") { echo "active"; } ?>">
<a href="/agent/transfers.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "transfers.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-exchange-alt"></i>
<p>Transfers</p>
</a>
</li>
<li class="nav-item">
<a href="trips.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "trips.php") { echo "active"; } ?>">
<a href="/agent/trips.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "trips.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-route"></i>
<p>Trips</p>
</a>
@@ -178,7 +178,7 @@
<?php if (lookupUserPermission("module_client") >= 1) { ?>
<li class="nav-item mt-3">
<a href="contacts.php" class="nav-link">
<a href="/agent/contacts.php" class="nav-link">
<i class="fas fa-users nav-icon"></i>
<p>Client Overview</p>
<i class="fas fa-angle-right nav-icon float-right"></i>
@@ -188,7 +188,7 @@
<?php if (lookupUserPermission("module_reporting") >= 1) { ?>
<li class="nav-item mt-3">
<a href="reports/" class="nav-link">
<a href="/agent/reports/" class="nav-link">
<i class="fas fa-chart-line nav-icon"></i>
<p>Reports</p>
<i class="fas fa-angle-right nav-icon float-right"></i>

View File

@@ -18,8 +18,8 @@ if (isset($_GET['invoice_id'])) {
$mysqli,
"SELECT * FROM invoices
LEFT JOIN clients ON invoice_client_id = client_id
LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1
LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1
LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
LEFT JOIN locations ON client_id = location_client_id AND location_primary = 1
WHERE invoice_id = $invoice_id
$access_permission_query
LIMIT 1"
@@ -162,8 +162,10 @@ if (isset($_GET['invoice_id'])) {
//Product autocomplete
$products_sql = mysqli_query($mysqli, "
SELECT
product_name AS label,
SELECT
CONCAT(product_code, ' - ', product_name) AS label,
product_name,
product_code,
product_type AS type,
product_description AS description,
product_price AS price,
@@ -188,7 +190,7 @@ if (isset($_GET['invoice_id'])) {
// Saved Payment Methods
$sql_saved_payment_methods = mysqli_query($mysqli, "
SELECT * FROM client_saved_payment_methods
LEFT JOIN payment_providers
LEFT JOIN payment_providers
ON client_saved_payment_methods.saved_payment_provider_id = payment_providers.payment_provider_id
WHERE saved_payment_client_id = $client_id
AND payment_provider_active = 1;
@@ -197,21 +199,12 @@ if (isset($_GET['invoice_id'])) {
?>
<ol class="breadcrumb d-print-none">
<?php if (isset($_GET['client_id'])) { ?>
<li class="breadcrumb-item">
<a href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
<a href="invoices.php">All Invoices</a>
</li>
<li class="breadcrumb-item">
<a href="invoices.php?client_id=<?php echo $client_id; ?>">Invoices</a>
<a href="invoices.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?> Invoices</a>
</li>
<?php } else { ?>
<li class="breadcrumb-item">
<a href="invoices.php">Invoices</a>
</li>
<li class="breadcrumb-item">
<a href="invoices.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
</li>
<?php } ?>
<li class="breadcrumb-item active"><?php echo "$invoice_prefix$invoice_number"; ?></li>
<?php if (isset($invoice_overdue)) { ?>
<span class="p-2 ml-2 badge badge-danger"><?php echo $invoice_overdue; ?></span>
@@ -247,12 +240,12 @@ if (isset($_GET['invoice_id'])) {
<?php if ($invoice_status !== 'Paid' && $invoice_status !== 'Cancelled' && $invoice_status !== 'Draft' && $invoice_status !== 'Non-Billable' && $invoice_amount != 0) { ?>
<div class="btn-group">
<button type="button" class="btn btn-success ajax-modal" data-modal-url="modals/invoice/invoice_pay.php?id=<?= $invoice_id ?>"><i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment</button>
<button type="button" class="btn btn-success ajax-modal" data-modal-url="modals/payment/payment_add.php?id=<?= $invoice_id ?>"><i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment</button>
<?php if (mysqli_num_rows($sql_saved_payment_methods) > 0 && ($invoice_status === 'Sent' || $invoice_status === 'Viewed')) { ?>
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/invoice/invoice_saved_method_pay.php?id=<?= $invoice_id ?>"><i class="fas fa-fw fa-wallet mr-2"></i>Pay with Saved Card</a>
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/payment/payment_saved_method_add.php?id=<?= $invoice_id ?>"><i class="fas fa-fw fa-wallet mr-2"></i>Pay with Saved Card</a>
</div>
<?php } ?>
@@ -284,7 +277,8 @@ if (isset($_GET['invoice_id'])) {
data-modal-url="modals/invoice/invoice_copy.php?id=<?= $invoice_id ?>">
<i class="fa fa-fw fa-copy text-secondary mr-2"></i>Copy
</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#addInvoiceRecurringModal<?php echo $invoice_id; ?>">
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/invoice/invoice_recurring_add.php?invoice_id=<?= $invoice_id ?>">
<i class="fa fa-fw fa-sync-alt text-secondary mr-2"></i>Recurring
</a>
<div class="dropdown-divider"></div>
@@ -463,10 +457,10 @@ if (isset($_GET['invoice_id'])) {
<textarea class="form-control" rows="2" id="desc" name="description" placeholder="Enter a Description"></textarea>
</td>
<td>
<input type="text" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: center;" id="qty" name="qty" placeholder="Qty">
<input type="text" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" class="form-control" style="text-align: center;" id="qty" name="qty" placeholder="Qty">
</td>
<td>
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" style="text-align: right;" id="price" name="price" placeholder="Price (<?php echo $invoice_currency_code; ?>)">
<input type="text" class="form-control" inputmode="decimal" pattern="-?[0-9]*\.?[0-9]{0,2}" style="text-align: right;" id="price" name="price" placeholder="Price (<?php echo $invoice_currency_code; ?>)">
</td>
<td>
<select class="form-control select2" name="tax_id" id="tax" required>
@@ -732,7 +726,6 @@ if (isset($_GET['invoice_id'])) {
</div>
<?php
include_once "modals/invoice/invoice_add_ticket.php";
include_once "modals/invoice/invoice_recurring_add.php";
include_once "modals/invoice/invoice_note.php";
}
@@ -747,12 +740,20 @@ require_once "../includes/footer.php";
<script>
$(function() {
var availableProducts = <?php echo $json_products ?? '[]'?>;
$("#name").autocomplete({
source: availableProducts,
minLength: 1,
delay: 0,
source: function(request, response) {
var term = $.ui.autocomplete.escapeRegex(request.term.toLowerCase());
var matcher = new RegExp(term, "i");
var matches = $.grep(availableProducts, function(item) {
return matcher.test(item.label) || matcher.test(item.product_name) || matcher.test(item.product_code);
});
response(matches);
},
select: function (event, ui) {
$("#name").val(ui.item.label);
$("#desc").val(ui.item.description);

Some files were not shown because too many files have changed in this diff Show More