mirror of
https://github.com/itflow-org/itflow
synced 2026-03-09 07:14:51 +00:00
Compare commits
312 Commits
undefined-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20e2f22a27 | ||
|
|
12b3775041 | ||
|
|
52b509fdc5 | ||
|
|
f9d0a8bf43 | ||
|
|
2349ef33d1 | ||
|
|
ccaf15268c | ||
|
|
616635f951 | ||
|
|
ce7daaf1cf | ||
|
|
fb9f5d986d | ||
|
|
3148906cfe | ||
|
|
6c057f4fd0 | ||
|
|
3014bba66d | ||
|
|
97958d5e22 | ||
|
|
1a7452cc27 | ||
|
|
34ba5d0570 | ||
|
|
c0fe9813dc | ||
|
|
fd29eb7c15 | ||
|
|
1bee085b33 | ||
|
|
1d06e6d9c8 | ||
|
|
bdf8038148 | ||
|
|
62fb2c91a1 | ||
|
|
376285ef62 | ||
|
|
d1eeba67fc | ||
|
|
2ca8112daf | ||
|
|
546f10bc82 | ||
|
|
ec7f1d561d | ||
|
|
8d54bc3a2f | ||
|
|
1d8f77f799 | ||
|
|
1c6795dd55 | ||
|
|
4d895a56e4 | ||
|
|
bdd56c91f7 | ||
|
|
be172b5bd9 | ||
|
|
d224d71f59 | ||
|
|
065630b975 | ||
|
|
decea604ab | ||
|
|
004b3b2bdc | ||
|
|
dca0cc34e9 | ||
|
|
9afb165fc4 | ||
|
|
6a6eb4a714 | ||
|
|
629f4e0c81 | ||
|
|
7cbe9bf7fc | ||
|
|
fc33312e79 | ||
|
|
563c0ea9c4 | ||
|
|
10d1a902d9 | ||
|
|
4079257739 | ||
|
|
91aba13c0d | ||
|
|
2cca4f2f0e | ||
|
|
d2e8dc1439 | ||
|
|
f3f9d0dd71 | ||
|
|
f6845a046f | ||
|
|
a50a4f274f | ||
|
|
6b6d847756 | ||
|
|
65d1f59e9b | ||
|
|
f39e6ccbc9 | ||
|
|
747b62d78c | ||
|
|
af0f3ac25f | ||
|
|
6aefe99c2f | ||
|
|
61c5595a68 | ||
|
|
3d11611699 | ||
|
|
38b4ed4b96 | ||
|
|
34308a5f9a | ||
|
|
118cc10804 | ||
|
|
ae3386f2d5 | ||
|
|
bf1ccc62f5 | ||
|
|
1ce4dd932e | ||
|
|
ff0bb49926 | ||
|
|
018642cbb8 | ||
|
|
bf1d0655c4 | ||
|
|
874b07f4d7 | ||
|
|
19fa210743 | ||
|
|
c8a6513d1c | ||
|
|
01288c8452 | ||
|
|
a60d3bb3a0 | ||
|
|
0470159c55 | ||
|
|
e1a93035fd | ||
|
|
c0b7a26905 | ||
|
|
704d770ec2 | ||
|
|
d42d2d99b1 | ||
|
|
ebfcc15927 | ||
|
|
4693aa3c93 | ||
|
|
07df657848 | ||
|
|
ef9436a1fb | ||
|
|
9318f42ce0 | ||
|
|
85c37d78a8 | ||
|
|
ff02ab0cea | ||
|
|
bd8bf026f0 | ||
|
|
644dc95380 | ||
|
|
f4935efed3 | ||
|
|
1712d34846 | ||
|
|
f0f1134be6 | ||
|
|
e0f7460e08 | ||
|
|
ae1d71dcd7 | ||
|
|
3cfe38c948 | ||
|
|
c1f0b63101 | ||
|
|
0a658d7cab | ||
|
|
3ed2582a9b | ||
|
|
2ea68776f6 | ||
|
|
c1ff22298f | ||
|
|
e94d2f93ea | ||
|
|
e7f6f8a4c7 | ||
|
|
4ffe75683b | ||
|
|
687920743d | ||
|
|
1a93149643 | ||
|
|
11d6654763 | ||
|
|
512d65c17a | ||
|
|
5a274061f3 | ||
|
|
a398ac7a8d | ||
|
|
41df4c4b9f | ||
|
|
7e7909cec1 | ||
|
|
7322bd66df | ||
|
|
39affa5528 | ||
|
|
374111c88d | ||
|
|
72fc0015bf | ||
|
|
7ab406b3f5 | ||
|
|
df280cd574 | ||
|
|
0a30300bde | ||
|
|
cb8b99d6ae | ||
|
|
1d3f29d385 | ||
|
|
c154113474 | ||
|
|
e02a6fc5e6 | ||
|
|
78040573d1 | ||
|
|
981f9ace04 | ||
|
|
208f7ac8f0 | ||
|
|
661f8db10b | ||
|
|
b48168ffec | ||
|
|
908ebb46d9 | ||
|
|
58bcb38617 | ||
|
|
1de023f9df | ||
|
|
5815ef2f75 | ||
|
|
e5dab8b1ca | ||
|
|
56c4b7fbe6 | ||
|
|
365b65e5b2 | ||
|
|
2193cd8d3e | ||
|
|
8b221bc055 | ||
|
|
77e4d2b566 | ||
|
|
88a29b7599 | ||
|
|
64525750b6 | ||
|
|
30499123f1 | ||
|
|
79703042ff | ||
|
|
ccd5605d97 | ||
|
|
908277065b | ||
|
|
f2d4eb0486 | ||
|
|
f784b659e8 | ||
|
|
e60a7a59f9 | ||
|
|
cab81ca170 | ||
|
|
a82e2c7ea1 | ||
|
|
a277380441 | ||
|
|
ad5710b1d8 | ||
|
|
3e3531a6ce | ||
|
|
a79ce23ae5 | ||
|
|
163aa3062e | ||
|
|
32f996d034 | ||
|
|
312eb4dffc | ||
|
|
1916456c84 | ||
|
|
9b8d37b577 | ||
|
|
05018e5f17 | ||
|
|
72ef918452 | ||
|
|
27fde82aff | ||
|
|
b27ffe6635 | ||
|
|
84cc4a094a | ||
|
|
e75600ee05 | ||
|
|
871ad2ea7e | ||
|
|
8b5f2e0f3f | ||
|
|
58d6ab7342 | ||
|
|
03570ecd04 | ||
|
|
ca5fb2e010 | ||
|
|
da561b296e | ||
|
|
523da0dea0 | ||
|
|
0e4cc76a84 | ||
|
|
7e39a7ed89 | ||
|
|
4a26ea7ed9 | ||
|
|
7c83ba15b9 | ||
|
|
10bfbed4bb | ||
|
|
81550bd7a8 | ||
|
|
a430bb917e | ||
|
|
e1a579387f | ||
|
|
fe8df66c67 | ||
|
|
5bb410f80c | ||
|
|
29b79b9d4e | ||
|
|
0f8a8d1464 | ||
|
|
cc92a4b7ee | ||
|
|
3ffef6df51 | ||
|
|
78e4787b99 | ||
|
|
540512a156 | ||
|
|
7737dbc65d | ||
|
|
faa94d888d | ||
|
|
99e2487d2b | ||
|
|
f09d8ffe05 | ||
|
|
c486e3fe62 | ||
|
|
ba2d6b6709 | ||
|
|
a388a279bc | ||
|
|
5a64b19a06 | ||
|
|
53178b8d20 | ||
|
|
0347382a34 | ||
|
|
840460afe7 | ||
|
|
c851e54e1d | ||
|
|
5ef53b569c | ||
|
|
698b4166e8 | ||
|
|
1a9a36829b | ||
|
|
155b8598ff | ||
|
|
4153c91f84 | ||
|
|
a99b19a1b5 | ||
|
|
18429fda2c | ||
|
|
435da991ec | ||
|
|
ebd9aae924 | ||
|
|
414a84d5ec | ||
|
|
a3b2517603 | ||
|
|
43535082f6 | ||
|
|
e73af9980e | ||
|
|
0bdd5784ee | ||
|
|
48719ce29c | ||
|
|
29839d3b23 | ||
|
|
185ea7d6ac | ||
|
|
ac7623d4f5 | ||
|
|
3d119261cc | ||
|
|
169619c9b9 | ||
|
|
b991f787a2 | ||
|
|
215fc6803e | ||
|
|
a79c1c8246 | ||
|
|
1aa6419b1b | ||
|
|
c7ef3627ce | ||
|
|
02694f6720 | ||
|
|
f50aabb570 | ||
|
|
19b8d09bfd | ||
|
|
66fb999a8c | ||
|
|
0c5883b61b | ||
|
|
ef66d5172c | ||
|
|
118f9a34d8 | ||
|
|
b61dfac569 | ||
|
|
79160f9b5c | ||
|
|
d2523cff4a | ||
|
|
1839599769 | ||
|
|
29e1b56e78 | ||
|
|
47e647c712 | ||
|
|
a87b0b0447 | ||
|
|
96b8fcad3a | ||
|
|
cf0fa0024c | ||
|
|
aba5ed9271 | ||
|
|
63141f3578 | ||
|
|
612041635d | ||
|
|
efcc0fd5cb | ||
|
|
b0724f5b66 | ||
|
|
66a2b4b6d2 | ||
|
|
77b4dfa50a | ||
|
|
1e6e7fd6d8 | ||
|
|
46a1b673ba | ||
|
|
7230325e62 | ||
|
|
af8e733cfb | ||
|
|
26ab43c57f | ||
|
|
15ed4ef1ce | ||
|
|
0ac76766bd | ||
|
|
abb97ad99f | ||
|
|
6cdc26b55b | ||
|
|
d1dcc5fb7e | ||
|
|
9f19fd3c75 | ||
|
|
61dedb7e7b | ||
|
|
65d2b8b2cb | ||
|
|
1d3f206660 | ||
|
|
ab46899e72 | ||
|
|
723a423b06 | ||
|
|
a837b97870 | ||
|
|
8be0789f25 | ||
|
|
99d017144d | ||
|
|
891f71006b | ||
|
|
d25017216a | ||
|
|
83b7c7b054 | ||
|
|
283c2a17df | ||
|
|
44de049f3b | ||
|
|
920d08f039 | ||
|
|
0cf1e338c2 | ||
|
|
293a2b800e | ||
|
|
650a099e19 | ||
|
|
46c2c8616e | ||
|
|
6295a5c878 | ||
|
|
39d8e19e16 | ||
|
|
9d3a44d110 | ||
|
|
54d46719c2 | ||
|
|
dbed2c17db | ||
|
|
f772ef2efd | ||
|
|
2f28f96f8d | ||
|
|
1f2bcf7c34 | ||
|
|
a9a5850fd4 | ||
|
|
09f3bfd8f4 | ||
|
|
3813fbf8f2 | ||
|
|
16001f8d4e | ||
|
|
49d3dbad9a | ||
|
|
56f32a4da2 | ||
|
|
a297b8d6d8 | ||
|
|
d365f48192 | ||
|
|
df6d955261 | ||
|
|
9fcaf9f5cc | ||
|
|
43a7b7faa5 | ||
|
|
69253385c5 | ||
|
|
cea7d61481 | ||
|
|
41f9a2e6e2 | ||
|
|
31d3659098 | ||
|
|
c12bfb157e | ||
|
|
a55dabb1cd | ||
|
|
06fec3c280 | ||
|
|
f733a27ad7 | ||
|
|
7ea39eb545 | ||
|
|
a85f898ef5 | ||
|
|
519975f3cf | ||
|
|
0e9a071e96 | ||
|
|
b09e4938b7 | ||
|
|
0d5bfdafdf | ||
|
|
d829e39b66 | ||
|
|
b11730303e | ||
|
|
49d127e957 | ||
|
|
e7353c4757 | ||
|
|
3106685972 | ||
|
|
58d43063ec |
16
.gitignore
vendored
16
.gitignore
vendored
@@ -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
|
||||
@@ -22,10 +32,6 @@ plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/URI/*
|
||||
plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/CSS/*
|
||||
!plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/CSS/.gitkeep
|
||||
.vscode/settings.json
|
||||
xcustom/*
|
||||
!xcustom/readme.php
|
||||
post/xcustom
|
||||
!post/xcustom/readme.php
|
||||
admin/custom/*
|
||||
!admin/custom/readme.php
|
||||
agent/custom/*
|
||||
@@ -43,5 +49,3 @@ setup/custom/*
|
||||
api/v1/custom/*
|
||||
!api/v1/custom/readme.php
|
||||
.zed
|
||||
|
||||
|
||||
|
||||
243
CHANGELOG.md
243
CHANGELOG.md
@@ -2,6 +2,247 @@
|
||||
|
||||
This file documents all notable changes made to ITFlow.
|
||||
|
||||
## [26.02.1] Maint Release
|
||||
### Bug Fixes
|
||||
- Credentials: Fix Password Generator.
|
||||
- Calendar: Restrict Events for client restricted agents.
|
||||
- Ticket Merge: Fix.
|
||||
- Asset Transfer: Fix.
|
||||
- Ticket Listing: Restrict Tickets presented in ticket list view from client restricted agents.
|
||||
- Ticket Details: Deny access to client restricted agents to view tickets without client_id in uri.
|
||||
- Tickets: Allow agents with restricted client access to view and edit tickets without a client.
|
||||
- Ticket Change client: Limit selection for agents with restricted client access.
|
||||
- Ticket Details: Don't display Updated at when null.
|
||||
|
||||
### New Features & Updates
|
||||
- Report: Added Client Detail Auditing.
|
||||
- API: Added Endpoint to retrieve time worked by agent.
|
||||
- ajax-modal: Revert to previous JS implementation before 26.02 release.
|
||||
- Ticket: Move Subject from Ticket main ticket header to ticket details card header.
|
||||
|
||||
## [26.02] Stable Release
|
||||
### Bug Fixes
|
||||
- Mail Parser - Do not automatically send new ticket notifications to noreply/donotreply addresses.
|
||||
- Ticket: removed newline \n on Parsed emails.
|
||||
- Show Trips for everyone if accounting module is enabled.
|
||||
- Fix Invoice Exporting.
|
||||
- Fix Billable Column not sorting correctly in tickets.
|
||||
- Fix Login flow where user agent and client user exists and agent has MFA but will not let them continue.
|
||||
- Fix passing missing user_id var in client portal.
|
||||
- Fix Ticket Templates not auto filling when selected.
|
||||
- Fix Invoices not being sent to all billings contacts when manaully sent.
|
||||
- Fix Documents and Files not able to be bulk deleted.
|
||||
- Fix Role Archiving, can be archived as long as no users are assigned to the role.
|
||||
- Fix showing Powered By ITFlow visibility on the login screen when Whitelabel is enabled.
|
||||
- Missing username in audit log on successful login due to missing passed user_id to logging.
|
||||
- API: Fix updating all documents instead of the intended document.
|
||||
- Documents: Fix Document created at not showing the correct creation date of the master document.
|
||||
- Ticket: Fixed Using edit ticket modal agent was not able to be set.
|
||||
- Always check if a user is archived and or disabled instead of just during login.
|
||||
- Report: Fix Collected tax report not totalling all tax categories.
|
||||
|
||||
### New Features & Updates
|
||||
- Task Approval System for ticket tasks: Once an approval is requested, the task cannot be marked as complete until approved. Internal Approvals Any other technician, or Specific technician, Client Approvals Anyone (usually the requestor) Tech contacts Billing contacts.
|
||||
- Printable Invoice Packing Slips now available.
|
||||
- Drastic Performance Bump: Up to 50% faster queries accross the board and reduced server memory usage by 40% by switching Database Query method from mysqli_fetch_array to mysqli_fetch_assoc.
|
||||
- Added Connect to Microsoft 365 Button to mail settings.
|
||||
- OAUTH2 support for Microsoft 365 and Google Workspaces is now considered stable and working.
|
||||
- Favorites: Assets and Credentials now can be favorited singly or by Bulk action. Favorited items appear in the client overview now.
|
||||
- Files/Documents: Collapsable folders feature, collapsed by default with a button to expand all.
|
||||
- URL Keys and such are now set to a more manageable 32 Characters by default.
|
||||
- Various UI/UX Updates throughout the app, with focus oin ticket details, contact details modal etc.
|
||||
- Added Show Archived files and documents to the files section.
|
||||
- Added Bulk Archive and restore options to files and documents.
|
||||
- Rewrite of the Kanban Ticket view to match our procedural style of coding.
|
||||
- All options are available in TinyMCE now in Mobile mode.
|
||||
- Agent names appear now in Invoice History section.
|
||||
- Mail Parser: Support flowed text.
|
||||
- Assets: Keep Purchase reference when copying.
|
||||
- Assets: Add basic tracking history: Archiving, restoring, name changes, transferimg to new clients.
|
||||
- Mail Parser: NDR Parsing.
|
||||
- Allow SVG files in mail attachments.
|
||||
- Tickets: Use a more friendly time worked instead of 02:41:00 translates to 2h 41m.
|
||||
- Update wording on ticket to invoice item details.
|
||||
- Merge Tickets: Now wth a ticket merge dropdown list of tickets instead of a text field.
|
||||
- Role Permissions can now be set during role creation, update Permission UI to use radio buttons instead of select boxes.
|
||||
- Bump TinyMCE 8.2.2 to 8.3.2.
|
||||
- Bump PHPMailer from 7.0.1 to 7.0.2.
|
||||
- Bump Datatables from 2.3.4 to 2.3.7.
|
||||
|
||||
## [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) weren’t 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 wasn’t 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 didn’t 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 there’s 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 +401,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.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<br />
|
||||
<a href="https://demo.itflow.org"><strong>View demo</strong></a>
|
||||
<br />
|
||||
Username: <b>demo@demo</b> | Password: <b>demo</b>
|
||||
Username: <b>demo@demo.com</b> | Password: <b>demo</b>
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://itflow.org/#about">About</a>
|
||||
@@ -93,6 +93,7 @@ If you want to improve ITFlow, feel free to fork the repo and create a pull requ
|
||||
We’re incredibly grateful to the organizations and individuals who support the project - a big thank you to:
|
||||
- CompuMatter
|
||||
- F1 for HELP
|
||||
- digiBandit
|
||||
- JetBrains (PhpStorm)
|
||||
|
||||
## License
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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">
|
||||
@@ -48,7 +58,7 @@ $num_rows = mysqli_num_rows($sql);
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$provider_id = intval($row['ai_provider_id']);
|
||||
$provider_name = nullable_htmlentities($row['ai_provider_name']);
|
||||
$model_id = intval($row['ai_model_id']);
|
||||
@@ -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";
|
||||
|
||||
@@ -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>
|
||||
@@ -48,7 +48,7 @@ $num_rows = mysqli_num_rows($sql);
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$provider_id = intval($row['ai_provider_id']);
|
||||
$provider_name = nullable_htmlentities($row['ai_provider_name']);
|
||||
$url = nullable_htmlentities($row['ai_provider_api_url']);
|
||||
@@ -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";
|
||||
|
||||
@@ -18,159 +18,156 @@ $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>Delete
|
||||
</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_assoc($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">
|
||||
<?php if ($api_key_expire > date("Y-m-d H:i:s")) { ?>
|
||||
<a class="dropdown-item text-danger text-bold confirm-link" href="post.php?revoke_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>
|
||||
<?php } ?>
|
||||
<?php if ($api_key_expire < date("Y-m-d H:i:s")) { ?>
|
||||
<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>Delete
|
||||
</a>
|
||||
<?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 "modals/api/api_key_add.php";
|
||||
|
||||
require_once "../includes/footer.php";
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
$sql_types_filter = mysqli_query($mysqli, "SELECT DISTINCT app_log_type FROM app_logs ORDER BY app_log_type ASC");
|
||||
while ($row = mysqli_fetch_array($sql_types_filter)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_types_filter)) {
|
||||
$log_type = nullable_htmlentities($row['app_log_type']);
|
||||
?>
|
||||
<option <?php if ($type_filter == $log_type) { echo "selected"; } ?>><?php echo $log_type; ?></option>
|
||||
@@ -85,7 +85,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
$sql_categories_filter = mysqli_query($mysqli, "SELECT DISTINCT app_log_category FROM app_logs ORDER BY app_log_category ASC");
|
||||
while ($row = mysqli_fetch_array($sql_categories_filter)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_categories_filter)) {
|
||||
$log_category = nullable_htmlentities($row['app_log_category']);
|
||||
?>
|
||||
<option <?php if ($category_filter == $log_category) { echo "selected"; } ?>><?php echo $log_category; ?></option>
|
||||
@@ -141,7 +141,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$log_id = intval($row['app_log_id']);
|
||||
$log_type = nullable_htmlentities($row['app_log_type']);
|
||||
$log_category = nullable_htmlentities($row['app_log_category']);
|
||||
|
||||
@@ -80,7 +80,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="input-group mb-3 mb-md-0">
|
||||
<select class="form-control select2" name="client" onchange="this.form.submit()">
|
||||
@@ -88,7 +88,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
$sql_clients_filter = mysqli_query($mysqli, "SELECT * FROM clients ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql_clients_filter)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_clients_filter)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_name = nullable_htmlentities($row['client_name']);
|
||||
?>
|
||||
@@ -108,7 +108,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
$sql_users_filter = mysqli_query($mysqli, "SELECT * FROM users ORDER BY user_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql_users_filter)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_users_filter)) {
|
||||
$user_id = intval($row['user_id']);
|
||||
$user_name = nullable_htmlentities($row['user_name']);
|
||||
?>
|
||||
@@ -128,7 +128,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
$sql_types_filter = mysqli_query($mysqli, "SELECT DISTINCT log_type FROM logs ORDER BY log_type ASC");
|
||||
while ($row = mysqli_fetch_array($sql_types_filter)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_types_filter)) {
|
||||
$log_type = nullable_htmlentities($row['log_type']);
|
||||
?>
|
||||
<option <?php if ($type_filter == $log_type) { echo "selected"; } ?>><?php echo $log_type; ?></option>
|
||||
@@ -147,7 +147,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
$sql_actions_filter = mysqli_query($mysqli, "SELECT DISTINCT log_action FROM logs ORDER BY log_action ASC");
|
||||
while ($row = mysqli_fetch_array($sql_actions_filter)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_actions_filter)) {
|
||||
$log_action = nullable_htmlentities($row['log_action']);
|
||||
?>
|
||||
<option <?php if ($action_filter == $log_action) { echo "selected"; } ?>><?php echo $log_action; ?></option>
|
||||
@@ -225,7 +225,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$log_id = intval($row['log_id']);
|
||||
$log_type = nullable_htmlentities($row['log_type']);
|
||||
$log_action = nullable_htmlentities($row['log_action']);
|
||||
@@ -280,4 +280,3 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
<?php
|
||||
require_once "../includes/footer.php";
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$category_id = intval($row['category_id']);
|
||||
$category_name = nullable_htmlentities($row['category_name']);
|
||||
$category_color = nullable_htmlentities($row['category_color']);
|
||||
|
||||
125
admin/contract_template.php
Normal file
125
admin/contract_template.php
Normal 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_assoc($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"; ?>
|
||||
@@ -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>
|
||||
|
||||
@@ -72,7 +72,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$custom_link_id = intval($row['custom_link_id']);
|
||||
$custom_link_name = nullable_htmlentities($row['custom_link_name']);
|
||||
$custom_link_uri = nullable_htmlentities($row['custom_link_uri']);
|
||||
@@ -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";
|
||||
|
||||
@@ -791,7 +791,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
|
||||
// Copy primary_location and primary_contact to their new vars in their own respecting tables
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM clients");
|
||||
while($row = mysqli_fetch_array($sql)) {
|
||||
while($row = mysqli_fetch_assoc($sql)) {
|
||||
$primary_contact = $row['primary_contact'];
|
||||
$primary_location = $row['primary_location'];
|
||||
|
||||
@@ -1666,7 +1666,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
if (CURRENT_DATABASE_VERSION == '1.3.9') {
|
||||
// Migrate all Network Info from Assets to Interface Table and make it primary interface
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM assets");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$asset_id = intval($row['asset_id']);
|
||||
$mac = sanitizeInput($row['asset_mac']);
|
||||
$ip = sanitizeInput($row['asset_ip']);
|
||||
@@ -1945,7 +1945,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
if (CURRENT_DATABASE_VERSION == '1.5.7') {
|
||||
// Create Users for contacts that have logins enabled and that are not archived
|
||||
$contacts_sql = mysqli_query($mysqli, "SELECT * FROM `contacts` WHERE contact_archived_at IS NULL AND (contact_auth_method = 'local' OR contact_auth_method = 'azure')");
|
||||
while($row = mysqli_fetch_array($contacts_sql)) {
|
||||
while($row = mysqli_fetch_assoc($contacts_sql)) {
|
||||
$contact_id = intval($row['contact_id']);
|
||||
$contact_name = mysqli_real_escape_string($mysqli, $row['contact_name']);
|
||||
$contact_email = mysqli_real_escape_string($mysqli, $row['contact_email']);
|
||||
@@ -2325,7 +2325,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
`interface_link_status` VARCHAR(50) NULL,
|
||||
`interface_link_created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`interface_link_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
|
||||
CONSTRAINT `fk_interface_a`
|
||||
FOREIGN KEY (`interface_a_id`)
|
||||
REFERENCES `asset_interfaces` (`interface_id`)
|
||||
@@ -3701,8 +3701,8 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
`ai_model_updated_at` DATETIME NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
`ai_model_ai_provider_id` INT(11) NOT NULL,
|
||||
PRIMARY KEY (`ai_model_id`),
|
||||
FOREIGN KEY (`ai_model_ai_provider_id`)
|
||||
REFERENCES `ai_providers`(`ai_provider_id`)
|
||||
FOREIGN KEY (`ai_model_ai_provider_id`)
|
||||
REFERENCES `ai_providers`(`ai_provider_id`)
|
||||
ON DELETE CASCADE
|
||||
)
|
||||
");
|
||||
@@ -3769,7 +3769,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.2.3') {
|
||||
|
||||
|
||||
mysqli_query($mysqli, "CREATE TABLE `credits` (
|
||||
`credit_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`credit_amount` DECIMAL(15,2) NOT NULL,
|
||||
@@ -3817,19 +3817,19 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
mysqli_query($mysqli, "ALTER TABLE `credits` ADD INDEX (`credit_client_id`)");
|
||||
mysqli_query($mysqli, "ALTER TABLE `credits` ADD INDEX (`credit_invoice_id`)");
|
||||
mysqli_query($mysqli, "ALTER TABLE `credits` ADD INDEX (`credit_created_at`)");
|
||||
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.7'");
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.2.7') {
|
||||
mysqli_query($mysqli, "ALTER TABLE `user_settings` ADD `user_config_theme_dark` TINYINT(1) NOT NULL DEFAULT 0 AFTER `user_config_signature`");
|
||||
mysqli_query($mysqli, "ALTER TABLE `settings` DROP `config_theme_dark`");
|
||||
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.8'");
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.2.8') {
|
||||
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `products` ADD `product_type` ENUM('service', 'product') NOT NULL DEFAULT 'service' AFTER `product_name`");
|
||||
mysqli_query($mysqli, "ALTER TABLE `products` ADD `product_code` VARCHAR(200) DEFAULT NULL AFTER `product_description`");
|
||||
mysqli_query($mysqli, "ALTER TABLE `products` ADD `product_location` VARCHAR(250) DEFAULT NULL AFTER `product_code`");
|
||||
@@ -3844,7 +3844,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
`stock_product_id` INT(11) NOT NULL,
|
||||
PRIMARY KEY (`stock_id`)
|
||||
)");
|
||||
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.2.9'");
|
||||
}
|
||||
|
||||
@@ -3853,7 +3853,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
|
||||
// Get Current Stripe Settings
|
||||
$sql_stripe_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1");
|
||||
$row = mysqli_fetch_array($sql_stripe_settings);
|
||||
$row = mysqli_fetch_assoc($sql_stripe_settings);
|
||||
$config_stripe_enable = intval($row['config_stripe_enable']);
|
||||
if ($config_stripe_enable === 1) {
|
||||
$config_stripe_publishable = mysqli_real_escape_string($mysqli, $row['config_stripe_publishable']);
|
||||
@@ -3879,7 +3879,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
|
||||
// Migrate Clients and Payment Method over
|
||||
$sql_stripe_clients = mysqli_query($mysqli, "SELECT * FROM client_stripe WHERE stripe_pm IS NOT NULL AND stripe_pm != ''");
|
||||
while ($row = mysqli_fetch_array($sql_stripe_clients)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_stripe_clients)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$stripe_id = mysqli_real_escape_string($mysqli, $row['stripe_id']);
|
||||
$stripe_pm = mysqli_real_escape_string($mysqli, $row['stripe_pm']);
|
||||
@@ -3931,13 +3931,13 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
if (CURRENT_DATABASE_VERSION == '2.3.0') {
|
||||
// Migrate Payment Methods from Categories Table to new payment_methods table
|
||||
$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Payment Method' AND category_name != 'Stripe' AND category_archived_at IS NULL");
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_categories)) {
|
||||
|
||||
while ($row = mysqli_fetch_assoc($sql_categories)) {
|
||||
$category_name = sanitizeInput($row['category_name']);
|
||||
|
||||
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = '$category_name'");
|
||||
}
|
||||
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.1'");
|
||||
}
|
||||
|
||||
@@ -3971,7 +3971,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.3.2') {
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE settings
|
||||
mysqli_query($mysqli, "ALTER TABLE settings
|
||||
ADD `config_imap_provider` ENUM('standard_imap','google_oauth','microsoft_oauth') NULL DEFAULT NULL AFTER `config_mail_from_name`,
|
||||
ADD `config_mail_oauth_client_id` VARCHAR(255) NULL AFTER `config_imap_provider`,
|
||||
ADD `config_mail_oauth_client_secret` VARCHAR(255) NULL AFTER `config_mail_oauth_client_id`,
|
||||
@@ -3986,7 +3986,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.3.3') {
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE settings
|
||||
mysqli_query($mysqli, "ALTER TABLE settings
|
||||
ADD `config_smtp_provider` ENUM('standard_smtp','google_oauth','microsoft_oauth') NULL DEFAULT NULL AFTER `config_start_page`
|
||||
");
|
||||
|
||||
@@ -4026,17 +4026,177 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.5'");
|
||||
}
|
||||
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.3.5') {
|
||||
mysqli_query($mysqli, "ALTER TABLE `settings` CHANGE `config_smtp_provider` `config_smtp_provider` VARCHAR(200) DEFAULT NULL");
|
||||
mysqli_query($mysqli, "ALTER TABLE `settings` CHANGE `config_imap_provider` `config_imap_provider` VARCHAR(200) DEFAULT NULL");
|
||||
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') {
|
||||
|
||||
mysqli_query($mysqli, "
|
||||
CREATE TABLE `task_approvals` (
|
||||
`approval_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`approval_scope` enum('client','internal') NOT NULL,
|
||||
`approval_type` enum('any','technical','billing','specific') NOT NULL,
|
||||
`approval_required_user_id` int(11) DEFAULT NULL,
|
||||
`approval_status` enum('pending','approved','declined') NOT NULL,
|
||||
`approval_created_by` int(11) NOT NULL,
|
||||
`approval_approved_by` varchar(255) DEFAULT NULL,
|
||||
`approval_url_key` varchar(200) NOT NULL,
|
||||
`approval_task_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`approval_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
");
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.9'");
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.3.9') {
|
||||
mysqli_query($mysqli, "ALTER TABLE `clients` ADD `client_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `client_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `locations` ADD `location_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `location_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `vendors` ADD `vendor_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `vendor_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `software` ADD `software_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `software_notes`");
|
||||
|
||||
mysqli_query(
|
||||
$mysqli,
|
||||
"ALTER TABLE `credentials`
|
||||
CHANGE `credential_important` `credential_favorite`
|
||||
TINYINT(1) NOT NULL DEFAULT 0
|
||||
AFTER `credential_note`"
|
||||
);
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `assets` DROP `asset_important`");
|
||||
mysqli_query($mysqli, "ALTER TABLE `assets` ADD `asset_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `asset_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `documents` DROP `document_important`");
|
||||
mysqli_query($mysqli, "ALTER TABLE `documents` ADD `document_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `document_client_visible`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `racks` ADD `rack_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `rack_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `files` DROP `file_important`");
|
||||
mysqli_query($mysqli, "ALTER TABLE `files` ADD `file_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `file_mime_type`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `networks` ADD `network_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `network_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `domain_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `certificates` ADD `certificate_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `certificate_notes`");
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE `services` ADD `service_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `service_notes`");
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.0'");
|
||||
}
|
||||
|
||||
// if (CURRENT_DATABASE_VERSION == '2.4.0') {
|
||||
// // Insert queries here required to update to DB version 2.4.1
|
||||
// // 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.4.1'");
|
||||
// }
|
||||
|
||||
} else {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -66,7 +66,7 @@
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$document_template_id = intval($row['document_template_id']);
|
||||
$document_template_name = nullable_htmlentities($row['document_template_name']);
|
||||
$document_template_description = nullable_htmlentities($row['document_template_description']);
|
||||
@@ -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";
|
||||
|
||||
@@ -15,9 +15,15 @@ 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");
|
||||
|
||||
$row = mysqli_fetch_array($sql_document);
|
||||
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_assoc($sql_document);
|
||||
|
||||
$document_template_name = nullable_htmlentities($row['document_template_name']);
|
||||
$document_template_description = nullable_htmlentities($row['document_template_description']);
|
||||
|
||||
@@ -27,12 +27,14 @@
|
||||
<p>Roles</p>
|
||||
</a>
|
||||
</li>
|
||||
<!-- 2025-12-05 JQ - Hide Permission Modules currently just shows modules
|
||||
<li class="nav-item">
|
||||
<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>
|
||||
@@ -67,31 +69,21 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/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="/admin/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="/admin/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="/admin/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="/admin/ticket_status.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'ticket_status.php' ? 'active' : ''); ?>">
|
||||
@@ -110,6 +102,17 @@
|
||||
<?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="/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>
|
||||
@@ -285,12 +288,12 @@
|
||||
</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"
|
||||
);
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_custom_links)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_custom_links)) {
|
||||
$custom_link_name = nullable_htmlentities($row['custom_link_name']);
|
||||
$custom_link_uri = sanitize_url($row['custom_link_uri']);
|
||||
$custom_link_icon = nullable_htmlentities($row['custom_link_icon']);
|
||||
|
||||
@@ -116,7 +116,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$email_id = intval($row['email_id']);
|
||||
$email_from = nullable_htmlentities($row['email_from']);
|
||||
$email_from_name = nullable_htmlentities($row['email_from_name']);
|
||||
|
||||
@@ -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>×</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>×</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_assoc($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';
|
||||
|
||||
@@ -6,7 +6,7 @@ $model_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models WHERE ai_model_id = $model_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$ai_model_ai_provider_id = intval($row['ai_model_ai_provider_id']);
|
||||
$model_id = intval($row['ai_model_id']);
|
||||
$model_name = nullable_htmlentities($row['ai_model_name']);
|
||||
@@ -39,7 +39,7 @@ ob_start();
|
||||
<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)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_ai_providers)) {
|
||||
$ai_provider_id = intval($row['ai_provider_id']);
|
||||
$ai_provider_name = nullable_htmlentities($row['ai_provider_name']);
|
||||
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -6,7 +6,7 @@ $provider_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_providers WHERE ai_provider_id = $provider_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$provider_name = nullable_htmlentities($row['ai_provider_name']);
|
||||
$url = nullable_htmlentities($row['ai_provider_api_url']);
|
||||
$key = nullable_htmlentities($row['ai_provider_api_key']);
|
||||
|
||||
@@ -1,121 +1,124 @@
|
||||
<?php
|
||||
$key = randomString(156);
|
||||
$decryptPW = randomString(160);
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$key = randomString(32);
|
||||
$decryptPW = randomString(32);
|
||||
|
||||
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>×</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>×</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_assoc($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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -6,7 +6,7 @@ $category_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_id = $category_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$category_name = nullable_htmlentities($row['category_name']);
|
||||
$category_color = nullable_htmlentities($row['category_color']);
|
||||
$category_type = nullable_htmlentities($row['category_type']);
|
||||
|
||||
221
admin/modals/contract_template/contract_template_add.php
Normal file
221
admin/modals/contract_template/contract_template_add.php
Normal 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>×</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';
|
||||
?>
|
||||
265
admin/modals/contract_template/contract_template_edit.php
Normal file
265
admin/modals/contract_template/contract_template_edit.php
Normal 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_assoc($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>×</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';
|
||||
?>
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once '../../../includes/modal_header.php';
|
||||
$custom_link_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM custom_links WHERE custom_link_id = $custom_link_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$custom_link_name = nullable_htmlentities($row['custom_link_name']);
|
||||
$custom_link_uri = nullable_htmlentities($row['custom_link_uri']);
|
||||
$custom_link_icon = nullable_htmlentities($row['custom_link_icon']);
|
||||
@@ -24,9 +24,9 @@ ob_start();
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
|
||||
|
||||
<input type="hidden" name="custom_link_id" value="<?php echo $custom_link_id; ?>">
|
||||
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once '../../../includes/modal_header.php';
|
||||
$document_template_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM document_templates WHERE document_template_id = $document_template_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$document_template_name = nullable_htmlentities($row['document_template_name']);
|
||||
$document_template_description = nullable_htmlentities($row['document_template_description']);
|
||||
$document_template_content = nullable_htmlentities($row['document_template_content']);
|
||||
|
||||
@@ -17,7 +17,7 @@ $purifier_config->set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'htt
|
||||
$purifier = new HTMLPurifier($purifier_config);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_id = $email_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
|
||||
$email_from = nullable_htmlentities($row['email_from']);
|
||||
$email_from_name = nullable_htmlentities($row['email_from_name']);
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -6,7 +6,7 @@ $payment_method_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM payment_methods WHERE payment_method_id = $payment_method_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$payment_method_id = intval($row['payment_method_id']);
|
||||
$payment_method_name = nullable_htmlentities($row['payment_method_name']);
|
||||
$payment_method_description = nullable_htmlentities($row['payment_method_description']);
|
||||
@@ -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">
|
||||
|
||||
@@ -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>×</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>×</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_assoc($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_assoc($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_assoc($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';
|
||||
|
||||
@@ -6,14 +6,14 @@ $provider_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM payment_providers WHERE payment_provider_id = $provider_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($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>×</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_assoc($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_assoc($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_assoc($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>
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -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>×</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_assoc($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>×</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';
|
||||
|
||||
@@ -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>×</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>×</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_assoc($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';
|
||||
|
||||
@@ -1,58 +1,213 @@
|
||||
<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>×</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>
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<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>×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
|
||||
<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-role-details">Details</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-role-permissions">Permissions</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
<!-- DETAILS TAB -->
|
||||
<div class="tab-pane fade show active" id="pills-role-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-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 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 class="form-group">
|
||||
<label>Admin Access <strong class="text-danger">*</strong></label>
|
||||
|
||||
<div class="custom-control custom-radio mb-2">
|
||||
<input type="radio" class="custom-control-input" id="admin_no" name="role_is_admin" value="0" checked required>
|
||||
<label class="custom-control-label" for="admin_no">
|
||||
No - use permissions on the next tab
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="custom-control custom-radio">
|
||||
<input type="radio" class="custom-control-input" id="admin_yes" name="role_is_admin" value="1" required>
|
||||
<label class="custom-control-label" for="admin_yes">
|
||||
Yes - this role should have full admin access
|
||||
</label>
|
||||
</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>
|
||||
|
||||
<!-- PERMISSIONS TAB -->
|
||||
<div class="tab-pane fade" id="pills-role-permissions">
|
||||
|
||||
<?php
|
||||
// Enumerate modules
|
||||
$sql_modules = mysqli_query($mysqli, "SELECT * FROM modules");
|
||||
while ($row_modules = mysqli_fetch_assoc($sql_modules)) {
|
||||
|
||||
$module_id = intval($row_modules['module_id']);
|
||||
|
||||
// raw for name, escaped for display
|
||||
$module_name_raw = $row_modules['module_name'];
|
||||
$module_name_display = ucfirst(str_replace("module_", "", $module_name_raw));
|
||||
|
||||
$module_name_display_safe = nullable_htmlentities($module_name_display);
|
||||
$module_description = nullable_htmlentities($row_modules['module_description']);
|
||||
|
||||
// default for new role
|
||||
$module_permission = 0;
|
||||
|
||||
$field_name = $module_id . "##" . $module_name_raw;
|
||||
$group_id = "perm_group_$module_id";
|
||||
?>
|
||||
|
||||
<div class="form-group">
|
||||
<label><?= $module_name_display_safe ?> <strong class="text-danger">*</strong></label>
|
||||
|
||||
<div class="btn-group btn-group-toggle btn-block" data-toggle="buttons" role="group"
|
||||
aria-label="Permissions for <?= $module_name_display_safe ?>">
|
||||
|
||||
<label class="btn btn-outline-secondary btn-sm active" title="No Access">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_0"
|
||||
value="0"
|
||||
autocomplete="off"
|
||||
checked
|
||||
required
|
||||
>
|
||||
None
|
||||
</label>
|
||||
|
||||
<label class="btn btn-outline-primary btn-sm" title="Viewing Only">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_1"
|
||||
value="1"
|
||||
autocomplete="off"
|
||||
>
|
||||
<i class="fas fa-fw fa-eye mr-1"></i>Read
|
||||
</label>
|
||||
|
||||
<label class="btn btn-outline-warning btn-sm" title="Read, Edit, Archive">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_2"
|
||||
value="2"
|
||||
autocomplete="off"
|
||||
>
|
||||
<i class="fas fa-fw fa-edit mr-1"></i>Modify
|
||||
</label>
|
||||
|
||||
<label class="btn btn-outline-danger btn-sm" title="Read, Edit, Archive, Delete">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_3"
|
||||
value="3"
|
||||
autocomplete="off"
|
||||
>
|
||||
<i class="fas fa-fw fa-trash mr-1"></i>Full
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
<small class="form-text text-muted mt-2"><?= $module_description ?></small>
|
||||
</div>
|
||||
|
||||
<?php } // end while ?>
|
||||
</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>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>
|
||||
// Optional: when Admin Yes is selected, disable permission radios + switch to Details tab
|
||||
(function () {
|
||||
function setPermissionsEnabled(enabled) {
|
||||
const permsTab = document.getElementById('pills-role-permissions');
|
||||
if (!permsTab) return;
|
||||
|
||||
permsTab.querySelectorAll('input[type="radio"]').forEach(function (el) {
|
||||
el.disabled = !enabled;
|
||||
});
|
||||
|
||||
// also visually dim the tab content
|
||||
permsTab.style.opacity = enabled ? '1' : '0.5';
|
||||
}
|
||||
|
||||
const adminYes = document.getElementById('admin_yes');
|
||||
const adminNo = document.getElementById('admin_no');
|
||||
|
||||
function refresh() {
|
||||
const isAdmin = adminYes && adminYes.checked;
|
||||
setPermissionsEnabled(!isAdmin);
|
||||
|
||||
if (isAdmin) {
|
||||
// move user back to Details tab (avoids confusion)
|
||||
const detailsTab = document.querySelector('a[href="#pills-role-details"]');
|
||||
if (detailsTab) detailsTab.click();
|
||||
}
|
||||
}
|
||||
|
||||
if (adminYes && adminNo) {
|
||||
adminYes.addEventListener('change', refresh);
|
||||
adminNo.addEventListener('change', refresh);
|
||||
refresh();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
||||
@@ -6,7 +6,7 @@ $role_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE role_id = $role_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$role_name = nullable_htmlentities($row['role_name']);
|
||||
$role_description = nullable_htmlentities($row['role_description']);
|
||||
$role_admin = intval($row['role_is_admin']);
|
||||
@@ -31,36 +31,36 @@ if (empty($user_names_string)) {
|
||||
$user_names_string = "-";
|
||||
}
|
||||
|
||||
|
||||
// Generate the HTML form content using output buffering.
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fas fa-fw fa-user-shield mr-2"></i>Editing role:
|
||||
<strong><?php echo $role_name; ?></strong></h5>
|
||||
<strong><?= $role_name ?></strong></h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</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'] ?>">
|
||||
<input type="hidden" name="role_id" value="<?php echo $role_id; ?>">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
<input type="hidden" name="role_id" value="<?= $role_id ?>">
|
||||
<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-role-details<?php echo $role_id; ?>">Details</a>
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-role-details">Details</a>
|
||||
</li>
|
||||
<?php if (!$role_admin) { ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-role-access<?php echo $role_id; ?>">Access</a>
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-role-permissions">Permissions</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
<div class="tab-pane fade show active" id="pills-role-details<?php echo $role_id; ?>">
|
||||
<div class="tab-pane fade show active" id="pills-role-details">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Name <strong class="text-danger">*</strong></label>
|
||||
@@ -68,7 +68,7 @@ ob_start();
|
||||
<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" value="<?php echo $role_name; ?>" required>
|
||||
<input type="text" class="form-control" name="role_name" placeholder="Role Name" maxlength="200" value="<?= $role_name ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -78,27 +78,33 @@ ob_start();
|
||||
<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" value="<?php echo $role_description; ?>" required>
|
||||
<input type="text" class="form-control" name="role_description" placeholder="Role Description" maxlength="200" value="<?= $role_description ?>" 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="1" <?php if ($role_admin) { echo 'selected'; } ?> >Yes - this role should have full admin access</option>
|
||||
<option value="0" <?php if (!$role_admin) { echo 'selected'; } ?>>No - use permissions on the next tab</option>
|
||||
</select>
|
||||
<div class="custom-control custom-radio mb-2">
|
||||
<input type="radio" class="custom-control-input" id="admin_yes" name="role_is_admin" value="1"
|
||||
<?php if ($role_admin) { echo 'checked'; } ?> required>
|
||||
<label class="custom-control-label" for="admin_yes">
|
||||
Yes - this role should have full admin access
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="custom-control custom-radio">
|
||||
<input type="radio" class="custom-control-input" id="admin_no" name="role_is_admin" value="0"
|
||||
<?php if (!$role_admin) { echo 'checked'; } ?> required>
|
||||
<label class="custom-control-label" for="admin_no">
|
||||
No - use permissions on the next tab
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-role-access<?php echo $role_id; ?>">
|
||||
<?php if (!$role_admin) { ?>
|
||||
<div class="tab-pane fade" id="pills-role-permissions">
|
||||
|
||||
<?php if ($role_admin) { ?>
|
||||
<div class="alert alert-warning"><strong>Module permissions do not apply to Admins.</strong></div>
|
||||
@@ -108,14 +114,14 @@ ob_start();
|
||||
|
||||
// Enumerate modules
|
||||
$sql_modules = mysqli_query($mysqli, "SELECT * FROM modules");
|
||||
while ($row_modules = mysqli_fetch_array($sql_modules)) {
|
||||
while ($row_modules = mysqli_fetch_assoc($sql_modules)) {
|
||||
$module_id = intval($row_modules['module_id']);
|
||||
$module_name = nullable_htmlentities($row_modules['module_name']);
|
||||
$module_name_display = ucfirst(str_replace("module_","",$module_name));
|
||||
$module_description = nullable_htmlentities($row_modules['module_description']);
|
||||
|
||||
// Get permission level for module
|
||||
$module_permission_row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT user_role_permission_level FROM user_role_permissions WHERE module_id = $module_id AND user_role_id = $role_id LIMIT 1"));
|
||||
$module_permission_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT user_role_permission_level FROM user_role_permissions WHERE module_id = $module_id AND user_role_id = $role_id LIMIT 1"));
|
||||
$module_permission = 0;
|
||||
if ($module_permission_row) {
|
||||
$module_permission = $module_permission_row['user_role_permission_level'];
|
||||
@@ -123,22 +129,73 @@ ob_start();
|
||||
?>
|
||||
|
||||
<div class="form-group">
|
||||
<label> <?php echo $module_name_display ?> <strong class="text-danger">*</strong></label>
|
||||
<div class="input-group">
|
||||
<select class="form-control select2" name="<?php echo "$module_id##$module_name" ?>" required>
|
||||
<option value="0" <?php if ($module_permission == 0) { echo 'selected'; } ?> >None</option>
|
||||
<option value="1" <?php if ($module_permission == 1) { echo 'selected'; } ?> >Read</option>
|
||||
<option value="2" <?php if ($module_permission == 2) { echo 'selected'; } ?>>Modify (Read, Edit, Archive)</option>
|
||||
<option value="3" <?php if ($module_permission == 3) { echo 'selected'; } ?>>Full (Read, Edit, Archive, Delete)</option>
|
||||
</select>
|
||||
<label> <?= $module_name_display ?> <strong class="text-danger">*</strong></label>
|
||||
<?php
|
||||
$field_name = "$module_id##$module_name";
|
||||
$group_id = "perm_group_$module_id";
|
||||
?>
|
||||
|
||||
<div class="btn-group btn-group-toggle btn-block" data-toggle="buttons" role="group" aria-label="Permissions for <?= $module_name_display ?>">
|
||||
|
||||
<label class="btn btn-outline-secondary btn-sm <?php if ($module_permission == 0) { echo 'active'; } ?>" title="No Access">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_0"
|
||||
value="0"
|
||||
autocomplete="off"
|
||||
<?php if ($module_permission == 0) { echo 'checked'; } ?>
|
||||
required
|
||||
>
|
||||
None
|
||||
</label>
|
||||
|
||||
<label class="btn btn-outline-primary btn-sm <?php if ($module_permission == 1) { echo 'active'; } ?>" title="Viewing Only">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_1"
|
||||
value="1"
|
||||
autocomplete="off"
|
||||
<?php if ($module_permission == 1) { echo 'checked'; } ?>
|
||||
>
|
||||
<i class="fas fa-fw fa-eye mr-1"></i>Read
|
||||
</label>
|
||||
|
||||
<label class="btn btn-outline-warning btn-sm <?php if ($module_permission == 2) { echo 'active'; } ?>" title="Read, Edit, Archive">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_2"
|
||||
value="2"
|
||||
autocomplete="off"
|
||||
<?php if ($module_permission == 2) { echo 'checked'; } ?>
|
||||
>
|
||||
<i class="fas fa-fw fa-edit mr-1"></i>Modify
|
||||
</label>
|
||||
|
||||
<label class="btn btn-outline-danger btn-sm <?php if ($module_permission == 3) { echo 'active'; } ?>" title="Read, Edit, Archive, Delete">
|
||||
<input
|
||||
type="radio"
|
||||
name="<?= $field_name ?>"
|
||||
id="<?= $group_id ?>_3"
|
||||
value="3"
|
||||
autocomplete="off"
|
||||
<?php if ($module_permission == 3) { echo 'checked'; } ?>
|
||||
>
|
||||
<i class="fas fa-fw fa-trash mr-1"></i>Full
|
||||
</label>
|
||||
|
||||
</div>
|
||||
<small class="form-text text-muted"><?php echo $module_description ?></small>
|
||||
|
||||
<small class="form-text text-muted mt-2"><?= $module_description ?></small>
|
||||
|
||||
</div>
|
||||
|
||||
<?php } // End while ?>
|
||||
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once '../../../includes/modal_header.php';
|
||||
$software_template_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM software_templates WHERE software_template_id = $software_template_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$software_name = nullable_htmlentities($row['software_template_name']);
|
||||
$software_version = nullable_htmlentities($row['software_template_version']);
|
||||
$software_description = nullable_htmlentities($row['software_template_description']);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -6,17 +6,30 @@ $tag_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM tags WHERE tag_id = $tag_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$tag_name = nullable_htmlentities($row['tag_name']);
|
||||
$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>×</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>
|
||||
|
||||
@@ -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">×</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">×</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';
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once '../../../includes/modal_header.php';
|
||||
$tax_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM taxes WHERE tax_id = $tax_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$tax_name = nullable_htmlentities($row['tax_name']);
|
||||
$tax_percent = floatval($row['tax_percent']);
|
||||
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once '../../../includes/modal_header.php';
|
||||
$ticket_status_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ticket_statuses WHERE ticket_status_id = $ticket_status_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$ticket_status_name = nullable_htmlentities($row['ticket_status_name']);
|
||||
$ticket_status_color = nullable_htmlentities($row['ticket_status_color']);
|
||||
$ticket_status_order = intval($row['ticket_status_order']);
|
||||
|
||||
@@ -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>×</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>×</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_assoc($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';
|
||||
|
||||
@@ -6,7 +6,7 @@ $task_template_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM task_templates WHERE task_template_id = $task_template_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$task_template_name = nullable_htmlentities($row['task_template_name']);
|
||||
$task_template_order = intval($row['task_template_order']);
|
||||
$task_template_completion_estimate = intval($row['task_template_completion_estimate']);
|
||||
@@ -25,7 +25,7 @@ ob_start();
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="task_template_id" value="<?php echo $task_template_id; ?>">
|
||||
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
@@ -47,7 +47,7 @@ ob_start();
|
||||
<input type="number" class="form-control" name="completion_estimate" placeholder="Estimated time to complete task in mins" value="<?php echo $task_template_completion_estimate; ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
||||
@@ -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>×</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>×</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_assoc($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_assoc($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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -6,7 +6,7 @@ $user_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE users.user_id = $user_id LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$user_name = nullable_htmlentities($row['user_name']);
|
||||
$user_email = nullable_htmlentities($row['user_email']);
|
||||
$user_avatar = nullable_htmlentities($row['user_avatar']);
|
||||
@@ -60,7 +60,7 @@ ob_start();
|
||||
<option value="0">No one</option>
|
||||
<?php
|
||||
$sql_users = mysqli_query($mysqli, "SELECT * FROM users WHERE user_type = 1 AND user_archived_at IS NULL");
|
||||
while ($row = mysqli_fetch_array($sql_users)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_users)) {
|
||||
$user_id_select = intval($row['user_id']);
|
||||
$user_name_select = nullable_htmlentities($row['user_name']);
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ require_once '../../../includes/modal_header.php';
|
||||
|
||||
$user_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users
|
||||
LEFT JOIN user_settings ON users.user_id = user_settings.user_id
|
||||
WHERE users.user_id = $user_id LIMIT 1"
|
||||
);
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$user_name = nullable_htmlentities($row['user_name']);
|
||||
$user_email = nullable_htmlentities($row['user_email']);
|
||||
$user_avatar = nullable_htmlentities($row['user_avatar']);
|
||||
@@ -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>
|
||||
|
||||
@@ -111,7 +114,7 @@ ob_start();
|
||||
<select class="form-control select2" name="role" required>
|
||||
<?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)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_user_roles)) {
|
||||
$role_id = intval($row['role_id']);
|
||||
$role_name = nullable_htmlentities($row['role_name']);
|
||||
|
||||
@@ -172,7 +175,7 @@ ob_start();
|
||||
<?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)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_client_select)) {
|
||||
$client_id_select = intval($row['client_id']);
|
||||
$client_name_select = nullable_htmlentities($row['client_name']);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -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>×</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>×</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";
|
||||
|
||||
@@ -6,7 +6,7 @@ $user_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $user_id AND user_archived_at IS NOT NULL LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$user_name = str_replace(" (archived)", "", $row['user_name']); //Removed (archived) from user_name
|
||||
$user_name = nullable_htmlentities($user_name);
|
||||
$user_email = nullable_htmlentities($row['user_email']);
|
||||
@@ -64,7 +64,7 @@ ob_start();
|
||||
<select class="form-control select2" name="role" required>
|
||||
<?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)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_user_roles)) {
|
||||
$role_id = intval($row['role_id']);
|
||||
$role_name = nullable_htmlentities($row['role_name']);
|
||||
|
||||
|
||||
@@ -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>×</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>×</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';
|
||||
|
||||
@@ -5,7 +5,7 @@ require_once '../../../includes/modal_header.php';
|
||||
$vendor_template_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM vendor_templates WHERE vendor_template_id = $vendor_template_id LIMIT 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$vendor_name = nullable_htmlentities($row['vendor_template_name']);
|
||||
$vendor_description = nullable_htmlentities($row['vendor_template_description']);
|
||||
$vendor_account_number = nullable_htmlentities($row['vendor_template_account_number']);
|
||||
@@ -233,7 +233,7 @@ ob_start();
|
||||
<div class="form-group">
|
||||
<textarea class="form-control" rows="8" placeholder="Enter some notes" name="notes"><?php echo $vendor_notes; ?></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label>Update Notes Globally?</label>
|
||||
<input type="checkbox" name="global_update_vendor_notes" value="1">
|
||||
|
||||
@@ -57,7 +57,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$module_id = intval($row['module_id']);
|
||||
$module_name = nullable_htmlentities($row['module_name']);
|
||||
$module_description = nullable_htmlentities($row['module_description']);
|
||||
|
||||
103
admin/oauth_microsoft_mail_callback.php
Normal file
103
admin/oauth_microsoft_mail_callback.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
require_once "../config.php";
|
||||
require_once "../functions.php";
|
||||
require_once "../includes/check_login.php";
|
||||
|
||||
$settings_mail_path = '/admin/settings_mail.php';
|
||||
|
||||
if (!isset($session_is_admin) || !$session_is_admin) {
|
||||
flash_alert("Admin access required.", 'error');
|
||||
redirect($settings_mail_path);
|
||||
}
|
||||
|
||||
$state = sanitizeInput($_GET['state'] ?? '');
|
||||
$code = $_GET['code'] ?? '';
|
||||
$error = sanitizeInput($_GET['error'] ?? '');
|
||||
$error_description = sanitizeInput($_GET['error_description'] ?? '');
|
||||
|
||||
$session_state = $_SESSION['mail_oauth_state'] ?? '';
|
||||
$session_state_expires = intval($_SESSION['mail_oauth_state_expires_at'] ?? 0);
|
||||
|
||||
unset($_SESSION['mail_oauth_state'], $_SESSION['mail_oauth_state_expires_at']);
|
||||
|
||||
if (!empty($error)) {
|
||||
$msg = "Microsoft OAuth authorization failed: $error";
|
||||
if (!empty($error_description)) {
|
||||
$msg .= " ($error_description)";
|
||||
}
|
||||
|
||||
flash_alert($msg, 'error');
|
||||
redirect($settings_mail_path);
|
||||
}
|
||||
|
||||
if (empty($state) || empty($code) || empty($session_state) || !hash_equals($session_state, $state) || time() > $session_state_expires) {
|
||||
flash_alert("Microsoft OAuth callback validation failed. Please try connecting again.", 'error');
|
||||
redirect($settings_mail_path);
|
||||
}
|
||||
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_tenant_id)) {
|
||||
flash_alert("Microsoft OAuth settings are incomplete. Please fill Client ID, Client Secret, and Tenant ID.", 'error');
|
||||
redirect($settings_mail_path);
|
||||
}
|
||||
|
||||
if (defined('BASE_URL') && !empty(BASE_URL)) {
|
||||
$base_url = rtrim((string) BASE_URL, '/');
|
||||
} else {
|
||||
$base_url = 'https://' . rtrim((string) $config_base_url, '/');
|
||||
}
|
||||
|
||||
$redirect_uri = $base_url . '/admin/oauth_microsoft_mail_callback.php';
|
||||
$token_url = 'https://login.microsoftonline.com/' . rawurlencode($config_mail_oauth_tenant_id) . '/oauth2/v2.0/token';
|
||||
$scope = 'offline_access openid profile https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send';
|
||||
|
||||
$ch = curl_init($token_url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
|
||||
'client_id' => $config_mail_oauth_client_id,
|
||||
'client_secret' => $config_mail_oauth_client_secret,
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'scope' => $scope,
|
||||
], '', '&'));
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
||||
|
||||
$raw_body = curl_exec($ch);
|
||||
$curl_err = curl_error($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($raw_body === false || $http_code < 200 || $http_code >= 300) {
|
||||
$reason = !empty($curl_err) ? $curl_err : "HTTP $http_code";
|
||||
flash_alert("Microsoft OAuth token exchange failed: $reason", 'error');
|
||||
redirect($settings_mail_path);
|
||||
}
|
||||
|
||||
$json = json_decode($raw_body, true);
|
||||
if (!is_array($json) || empty($json['refresh_token']) || empty($json['access_token'])) {
|
||||
flash_alert("Microsoft OAuth token exchange failed: refresh token or access token missing.", 'error');
|
||||
redirect($settings_mail_path);
|
||||
}
|
||||
|
||||
$refresh_token = (string) $json['refresh_token'];
|
||||
$access_token = (string) $json['access_token'];
|
||||
$expires_at = date('Y-m-d H:i:s', time() + (int)($json['expires_in'] ?? 3600));
|
||||
|
||||
$refresh_token_esc = mysqli_real_escape_string($mysqli, $refresh_token);
|
||||
$access_token_esc = mysqli_real_escape_string($mysqli, $access_token);
|
||||
$expires_at_esc = mysqli_real_escape_string($mysqli, $expires_at);
|
||||
|
||||
mysqli_query($mysqli, "UPDATE settings SET
|
||||
config_imap_provider = 'microsoft_oauth',
|
||||
config_smtp_provider = 'microsoft_oauth',
|
||||
config_mail_oauth_refresh_token = '$refresh_token_esc',
|
||||
config_mail_oauth_access_token = '$access_token_esc',
|
||||
config_mail_oauth_access_token_expires_at = '$expires_at_esc'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name completed Microsoft OAuth connect flow for mail settings");
|
||||
flash_alert("Microsoft OAuth connected successfully. Token expires at $expires_at.");
|
||||
redirect($settings_mail_path);
|
||||
@@ -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">
|
||||
@@ -45,7 +45,7 @@ $num_rows = mysqli_num_rows($sql);
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$payment_method_id = intval($row['payment_method_id']);
|
||||
$payment_method_name = nullable_htmlentities($row['payment_method_name']);
|
||||
$payment_method_description = nullable_htmlentities($row['payment_method_description']);
|
||||
@@ -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";
|
||||
|
||||
@@ -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>
|
||||
@@ -66,13 +66,13 @@ $num_rows = mysqli_num_rows($sql);
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$provider_id = intval($row['payment_provider_id']);
|
||||
$provider_name = nullable_htmlentities($row['payment_provider_name']);
|
||||
$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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -31,6 +31,27 @@ if (isset($_POST['add_api_key'])) {
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['revoke_api_key'])) {
|
||||
|
||||
validateCSRFToken($_GET['csrf_token']);
|
||||
|
||||
$api_key_id = intval($_GET['revoke_api_key']);
|
||||
|
||||
// Get API Key Name
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT api_key_name, api_key_client_id FROM api_keys WHERE api_key_id = $api_key_id"));
|
||||
$api_key_name = sanitizeInput($row['api_key_name']);
|
||||
$client_id = intval($row['api_key_client_id']);
|
||||
|
||||
mysqli_query($mysqli,"UPDATE api_keys SET api_key_expire = NOW() WHERE api_key_id = $api_key_id");
|
||||
|
||||
logAction("API Key", "Revoke", "$session_name revoked API key $name", $client_id);
|
||||
|
||||
flash_alert("API Key <strong>$name</strong> revoked", 'error');
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['delete_api_key'])) {
|
||||
|
||||
validateCSRFToken($_GET['csrf_token']);
|
||||
@@ -38,7 +59,7 @@ if (isset($_GET['delete_api_key'])) {
|
||||
$api_key_id = intval($_GET['delete_api_key']);
|
||||
|
||||
// Get API Key Name
|
||||
$row = mysqli_fetch_array(mysqli_query($mysqli,"SELECT api_key_name, api_key_client_id FROM api_keys WHERE api_key_id = $api_key_id"));
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT api_key_name, api_key_client_id FROM api_keys WHERE api_key_id = $api_key_id"));
|
||||
$api_key_name = sanitizeInput($row['api_key_name']);
|
||||
$client_id = intval($row['api_key_client_id']);
|
||||
|
||||
@@ -64,9 +85,9 @@ if (isset($_POST['bulk_delete_api_keys'])) {
|
||||
foreach ($_POST['api_key_ids'] as $api_key_id) {
|
||||
|
||||
$api_key_id = intval($api_key_id);
|
||||
|
||||
|
||||
// Get API Key Name
|
||||
$row = mysqli_fetch_array(mysqli_query($mysqli,"SELECT api_key_name, api_key_client_id FROM api_keys WHERE api_key_id = $api_key_id"));
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT api_key_name, api_key_client_id FROM api_keys WHERE api_key_id = $api_key_id"));
|
||||
$api_key_name = sanitizeInput($row['api_key_name']);
|
||||
$client_id = intval($row['api_key_client_id']);
|
||||
|
||||
|
||||
@@ -307,11 +307,11 @@ if (isset($_POST['backup_master_key'])) {
|
||||
$password = $_POST['password'];
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $session_user_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
|
||||
if (password_verify($password, $row['user_password'])) {
|
||||
$site_encryption_master_key = decryptUserSpecificKey($row['user_specific_encryption_ciphertext'], $password);
|
||||
|
||||
|
||||
logAction("Master Key", "Download", "$session_name retrieved the master encryption key");
|
||||
|
||||
appNotify("Master Key", "$session_name retrieved the master encryption key");
|
||||
@@ -320,13 +320,12 @@ if (isset($_POST['backup_master_key'])) {
|
||||
echo "<br>Master encryption key:<br>";
|
||||
echo "<b>$site_encryption_master_key</b>";
|
||||
echo "<br>==============================";
|
||||
|
||||
|
||||
} else {
|
||||
logAction("Master Key", "Download", "$session_name attempted to retrieve the master encryption key but failed");
|
||||
|
||||
flash_alert("Incorrect password.", 'error');
|
||||
|
||||
|
||||
redirect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,12 +39,12 @@ if (isset($_POST['edit_category'])) {
|
||||
}
|
||||
|
||||
if (isset($_GET['archive_category'])) {
|
||||
|
||||
|
||||
$category_id = intval($_GET['archive_category']);
|
||||
|
||||
// Get Category Name and Type for logging
|
||||
$sql = mysqli_query($mysqli,"SELECT category_name, category_type FROM categories WHERE category_id = $category_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$category_name = sanitizeInput($row['category_name']);
|
||||
$category_type = sanitizeInput($row['category_type']);
|
||||
|
||||
@@ -59,12 +59,12 @@ if (isset($_GET['archive_category'])) {
|
||||
}
|
||||
|
||||
if (isset($_GET['unarchive_category'])) {
|
||||
|
||||
|
||||
$category_id = intval($_GET['unarchive_category']);
|
||||
|
||||
// Get Category Name and Type for logging
|
||||
$sql = mysqli_query($mysqli,"SELECT category_name, category_type FROM categories WHERE category_id = $category_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$category_name = sanitizeInput($row['category_name']);
|
||||
$category_type = sanitizeInput($row['category_type']);
|
||||
|
||||
@@ -79,12 +79,12 @@ if (isset($_GET['unarchive_category'])) {
|
||||
}
|
||||
|
||||
if (isset($_GET['delete_category'])) {
|
||||
|
||||
|
||||
$category_id = intval($_GET['delete_category']);
|
||||
|
||||
// Get Category Name and Type for logging
|
||||
$sql = mysqli_query($mysqli,"SELECT category_name, category_type FROM categories WHERE category_id = $category_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$category_name = sanitizeInput($row['category_name']);
|
||||
$category_type = sanitizeInput($row['category_type']);
|
||||
|
||||
|
||||
157
admin/post/contract_template.php
Normal file
157
admin/post/contract_template.php
Normal 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();
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -48,12 +48,12 @@ if (isset($_POST['edit_custom_link'])) {
|
||||
}
|
||||
|
||||
if (isset($_GET['delete_custom_link'])) {
|
||||
|
||||
|
||||
$custom_link_id = intval($_GET['delete_custom_link']);
|
||||
|
||||
// Get Custom Link name and uri for logging
|
||||
$sql = mysqli_query($mysqli,"SELECT custom_link_name, custom_link_uri FROM custom_links WHERE custom_link_id = $custom_link_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$custom_link_name = sanitizeInput($row['custom_link_name']);
|
||||
$custom_link_uri = sanitizeInput($row['custom_link_uri']);
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,9 +18,23 @@ if (isset($_POST['add_role'])) {
|
||||
|
||||
$role_id = mysqli_insert_id($mysqli);
|
||||
|
||||
// Insert role permissions (only if not admin)
|
||||
if ($admin == 0) {
|
||||
foreach ($_POST as $key => $value) {
|
||||
if (str_contains($key, '##module_')) {
|
||||
$module_id = intval(explode('##', $key)[0]);
|
||||
$access_level = intval($value);
|
||||
|
||||
if ($access_level > 0) {
|
||||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = $role_id, module_id = $module_id, user_role_permission_level = $access_level");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logAction("User Role", "Create", "$session_name created user role $name", 0, $role_id);
|
||||
|
||||
flash_alert("User Role <strong$name</strong> created");
|
||||
flash_alert("User Role <strong>$name</strong> created");
|
||||
|
||||
redirect();
|
||||
|
||||
@@ -34,7 +48,7 @@ if (isset($_POST['edit_role'])) {
|
||||
$name = sanitizeInput($_POST['role_name']);
|
||||
$description = sanitizeInput($_POST['role_description']);
|
||||
$admin = intval($_POST['role_is_admin']);
|
||||
|
||||
|
||||
mysqli_query($mysqli, "UPDATE user_roles SET role_name = '$name', role_description = '$description', role_is_admin = $admin WHERE role_id = $role_id");
|
||||
|
||||
// Update role access levels
|
||||
@@ -70,18 +84,18 @@ if (isset($_GET['archive_role'])) {
|
||||
$role_user_count = mysqli_fetch_row($sql_role_user_count)[0];
|
||||
if ($role_user_count != 0) {
|
||||
flash_alert("Role must not in use to archive it", 'error');
|
||||
|
||||
|
||||
redirect();
|
||||
}
|
||||
|
||||
mysqli_query($mysqli, "UPDATE user_roles SET role_archived_at = NOW() WHERE role_id = $role_id");
|
||||
|
||||
$role_name = sanitizeInput(getFieldById('roles', $role_id, 'role_name'));
|
||||
$role_name = sanitizeInput(getFieldById('user_roles', $role_id, 'role_name'));
|
||||
|
||||
logAction("User Role", "Archive", "$session_name archived user role $role_name", 0, $role_id);
|
||||
|
||||
flash_alert("User Role <strong>$role_name</strong> archived", 'error');
|
||||
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
if (isset($_GET['delete_saved_payment'])) {
|
||||
|
||||
|
||||
validateCSRFToken($_GET['csrf_token']);
|
||||
|
||||
$saved_payment_id = intval($_GET['delete_saved_payment']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "
|
||||
SELECT
|
||||
SELECT
|
||||
client_saved_payment_methods.saved_payment_id,
|
||||
client_saved_payment_methods.saved_payment_client_id,
|
||||
client_saved_payment_methods.saved_payment_provider_id,
|
||||
@@ -27,7 +27,7 @@ if (isset($_GET['delete_saved_payment'])) {
|
||||
WHERE client_saved_payment_methods.saved_payment_id = $saved_payment_id"
|
||||
);
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$client_id = intval($row['saved_payment_client_id']);
|
||||
$provider_id = intval($row['saved_payment_provider_id']);
|
||||
$payment_provider_name = nullable_htmlentities($row['payment_provider_name']);
|
||||
@@ -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,15 +56,15 @@ 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.
|
||||
|
||||
logAction("Payment Provider", "Update", "$session_name deleted saved payment method $saved_payment_description (PM: $payment_method)", $client_id);
|
||||
|
||||
|
||||
flash_alert("Payment method <strong>$saved_payment_description</strong> removed", 'error');
|
||||
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ if (isset($_POST['edit_company'])) {
|
||||
$tax_id = sanitizeInput($_POST['tax_id']);
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT company_logo FROM companies WHERE company_id = 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$existing_file_name = sanitizeInput($row['company_logo']);
|
||||
|
||||
// Company logo
|
||||
@@ -55,7 +55,7 @@ if (isset($_POST['edit_company'])) {
|
||||
if (isset($_GET['remove_company_logo'])) {
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT company_logo FROM companies");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$company_logo = $row['company_logo']; // FileSystem Operation Logo is already sanitized
|
||||
|
||||
unlink("../uploads/settings/$company_logo");
|
||||
|
||||
@@ -1,186 +1,582 @@
|
||||
<?php
|
||||
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
if (isset($_POST['edit_mail_smtp_settings'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_smtp_provider = sanitizeInput($_POST['config_smtp_provider']);
|
||||
$config_smtp_host = sanitizeInput($_POST['config_smtp_host']);
|
||||
$config_smtp_port = intval($_POST['config_smtp_port'] ?? 0);
|
||||
$config_smtp_encryption = sanitizeInput($_POST['config_smtp_encryption']);
|
||||
$config_smtp_username = sanitizeInput($_POST['config_smtp_username']);
|
||||
$config_smtp_password = sanitizeInput($_POST['config_smtp_password']);
|
||||
|
||||
// Shared OAuth fields
|
||||
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
|
||||
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
|
||||
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']);
|
||||
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
|
||||
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']);
|
||||
|
||||
mysqli_query($mysqli, "
|
||||
UPDATE settings SET
|
||||
config_smtp_provider = '$config_smtp_provider',
|
||||
config_smtp_host = '$config_smtp_host',
|
||||
config_smtp_port = $config_smtp_port,
|
||||
config_smtp_encryption = '$config_smtp_encryption',
|
||||
config_smtp_username = '$config_smtp_username',
|
||||
config_smtp_password = '$config_smtp_password',
|
||||
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
|
||||
config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
|
||||
config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
|
||||
config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
|
||||
config_mail_oauth_access_token = '$config_mail_oauth_access_token'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited SMTP settings");
|
||||
|
||||
flash_alert("SMTP Mail Settings updated");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_imap_settings'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_imap_provider = sanitizeInput($_POST['config_imap_provider']);
|
||||
$config_imap_host = sanitizeInput($_POST['config_imap_host']);
|
||||
$config_imap_port = intval($_POST['config_imap_port'] ?? 0);
|
||||
$config_imap_encryption = sanitizeInput($_POST['config_imap_encryption']);
|
||||
$config_imap_username = sanitizeInput($_POST['config_imap_username']);
|
||||
$config_imap_password = sanitizeInput($_POST['config_imap_password']);
|
||||
|
||||
// Shared OAuth fields
|
||||
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
|
||||
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
|
||||
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']);
|
||||
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
|
||||
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']);
|
||||
|
||||
mysqli_query($mysqli, "
|
||||
UPDATE settings SET
|
||||
config_imap_provider = '$config_imap_provider',
|
||||
config_imap_host = '$config_imap_host',
|
||||
config_imap_port = $config_imap_port,
|
||||
config_imap_encryption = '$config_imap_encryption',
|
||||
config_imap_username = '$config_imap_username',
|
||||
config_imap_password = '$config_imap_password',
|
||||
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
|
||||
config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
|
||||
config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
|
||||
config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
|
||||
config_mail_oauth_access_token = '$config_mail_oauth_access_token'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited IMAP settings");
|
||||
|
||||
flash_alert("IMAP Mail Settings updated");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_from_settings'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_mail_from_email = sanitizeInput(filter_var($_POST['config_mail_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_mail_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_mail_from_name']));
|
||||
|
||||
$config_invoice_from_email = sanitizeInput(filter_var($_POST['config_invoice_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_invoice_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_invoice_from_name']));
|
||||
|
||||
$config_quote_from_email = sanitizeInput(filter_var($_POST['config_quote_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_quote_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_quote_from_name']));
|
||||
|
||||
$config_ticket_from_email = sanitizeInput(filter_var($_POST['config_ticket_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_ticket_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_ticket_from_name']));
|
||||
|
||||
mysqli_query($mysqli,"UPDATE settings SET config_mail_from_email = '$config_mail_from_email', config_mail_from_name = '$config_mail_from_name', config_invoice_from_email = '$config_invoice_from_email', config_invoice_from_name = '$config_invoice_from_name', config_quote_from_email = '$config_quote_from_email', config_quote_from_name = '$config_quote_from_name', config_ticket_from_email = '$config_ticket_from_email', config_ticket_from_name = '$config_ticket_from_name' WHERE company_id = 1");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited mail from settings");
|
||||
|
||||
flash_alert("Mail From Settings updated");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['test_email_smtp'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$test_email = intval($_POST['test_email']);
|
||||
|
||||
if($test_email == 1) {
|
||||
$email_from = sanitizeInput($config_mail_from_email);
|
||||
$email_from_name = sanitizeInput($config_mail_from_name);
|
||||
} elseif ($test_email == 2) {
|
||||
$email_from = sanitizeInput($config_invoice_from_email);
|
||||
$email_from_name = sanitizeInput($config_invoice_from_name);
|
||||
} elseif ($test_email == 3) {
|
||||
$email_from = sanitizeInput($config_quote_from_email);
|
||||
$email_from_name = sanitizeInput($config_quote_from_name);
|
||||
} else {
|
||||
$email_from = sanitizeInput($config_ticket_from_email);
|
||||
$email_from_name = sanitizeInput($config_ticket_from_name);
|
||||
}
|
||||
|
||||
$email_to = sanitizeInput($_POST['email_to']);
|
||||
$subject = "Test email from ITFlow";
|
||||
$body = "This is a test email from ITFlow. If you are reading this, it worked!";
|
||||
|
||||
$data = [
|
||||
[
|
||||
'from' => $email_from,
|
||||
'from_name' => $email_from_name,
|
||||
'recipient' => $email_to,
|
||||
'recipient_name' => 'Chap',
|
||||
'subject' => $subject,
|
||||
'body' => $body
|
||||
]
|
||||
];
|
||||
|
||||
$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>");
|
||||
} else {
|
||||
flash_alert("Failed to add test mail to queue", 'error');
|
||||
}
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
try {
|
||||
$inbox = @imap_open($hostname, $username, $password);
|
||||
|
||||
if ($inbox) {
|
||||
imap_close($inbox);
|
||||
flash_alert("Connected successfully");
|
||||
} else {
|
||||
throw new Exception(imap_last_error());
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
flash_alert("<strong>IMAP connection failed:</strong> " . $e->getMessage(), 'error');
|
||||
}
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
<?php
|
||||
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
if (!defined('MICROSOFT_OAUTH_BASE_URL')) {
|
||||
define('MICROSOFT_OAUTH_BASE_URL', 'https://login.microsoftonline.com/');
|
||||
}
|
||||
|
||||
if (isset($_POST['oauth_connect_microsoft_mail'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
// Save current IMAP/OAuth form values first so auth flow always uses latest inputs.
|
||||
$config_imap_provider = sanitizeInput($_POST['config_imap_provider'] ?? '');
|
||||
$config_imap_username = sanitizeInput($_POST['config_imap_username'] ?? '');
|
||||
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id'] ?? '');
|
||||
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret'] ?? '');
|
||||
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id'] ?? '');
|
||||
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token'] ?? '');
|
||||
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token'] ?? '');
|
||||
|
||||
mysqli_query($mysqli, "UPDATE settings SET
|
||||
config_imap_provider = '$config_imap_provider',
|
||||
config_imap_username = '$config_imap_username',
|
||||
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
|
||||
config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
|
||||
config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
|
||||
config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
|
||||
config_mail_oauth_access_token = '$config_mail_oauth_access_token'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
if ($config_imap_provider !== 'microsoft_oauth') {
|
||||
flash_alert("Please set IMAP Provider to Microsoft 365 (OAuth) before connecting.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_tenant_id)) {
|
||||
flash_alert("Missing Microsoft OAuth settings. Please provide Client ID, Client Secret, and Tenant ID first.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
if (defined('BASE_URL') && !empty(BASE_URL)) {
|
||||
$base_url = rtrim((string) BASE_URL, '/');
|
||||
} else {
|
||||
$base_url = 'https://' . rtrim((string) $config_base_url, '/');
|
||||
}
|
||||
|
||||
$redirect_uri = $base_url . '/admin/oauth_microsoft_mail_callback.php';
|
||||
|
||||
try {
|
||||
$state = bin2hex(random_bytes(32));
|
||||
} catch (Throwable $e) {
|
||||
$state = sha1(uniqid((string) mt_rand(), true));
|
||||
}
|
||||
|
||||
$_SESSION['mail_oauth_state'] = $state;
|
||||
$_SESSION['mail_oauth_state_expires_at'] = time() + 600;
|
||||
|
||||
$scope = 'offline_access openid profile https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send';
|
||||
|
||||
$authorize_url = MICROSOFT_OAUTH_BASE_URL . rawurlencode($config_mail_oauth_tenant_id) . '/oauth2/v2.0/authorize?'
|
||||
. http_build_query([
|
||||
'client_id' => $config_mail_oauth_client_id,
|
||||
'response_type' => 'code',
|
||||
'redirect_uri' => $redirect_uri,
|
||||
'response_mode' => 'query',
|
||||
'scope' => $scope,
|
||||
'state' => $state,
|
||||
'prompt' => 'consent',
|
||||
], '', '&', PHP_QUERY_RFC3986);
|
||||
|
||||
logAction("Settings", "Edit", "$session_name started Microsoft OAuth connect flow for mail settings");
|
||||
|
||||
redirect($authorize_url);
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_smtp_settings'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_smtp_provider = sanitizeInput($_POST['config_smtp_provider']);
|
||||
$config_smtp_host = sanitizeInput($_POST['config_smtp_host']);
|
||||
$config_smtp_port = intval($_POST['config_smtp_port'] ?? 0);
|
||||
$config_smtp_encryption = sanitizeInput($_POST['config_smtp_encryption']);
|
||||
$config_smtp_username = sanitizeInput($_POST['config_smtp_username']);
|
||||
$config_smtp_password = sanitizeInput($_POST['config_smtp_password']);
|
||||
|
||||
// Shared OAuth fields
|
||||
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
|
||||
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
|
||||
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']);
|
||||
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
|
||||
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']);
|
||||
|
||||
mysqli_query($mysqli, "
|
||||
UPDATE settings SET
|
||||
config_smtp_provider = '$config_smtp_provider',
|
||||
config_smtp_host = '$config_smtp_host',
|
||||
config_smtp_port = $config_smtp_port,
|
||||
config_smtp_encryption = '$config_smtp_encryption',
|
||||
config_smtp_username = '$config_smtp_username',
|
||||
config_smtp_password = '$config_smtp_password',
|
||||
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
|
||||
config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
|
||||
config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
|
||||
config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
|
||||
config_mail_oauth_access_token = '$config_mail_oauth_access_token'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited SMTP settings");
|
||||
|
||||
flash_alert("SMTP Mail Settings updated");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_imap_settings'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_imap_provider = sanitizeInput($_POST['config_imap_provider']);
|
||||
$config_imap_host = sanitizeInput($_POST['config_imap_host']);
|
||||
$config_imap_port = intval($_POST['config_imap_port'] ?? 0);
|
||||
$config_imap_encryption = sanitizeInput($_POST['config_imap_encryption']);
|
||||
$config_imap_username = sanitizeInput($_POST['config_imap_username']);
|
||||
$config_imap_password = sanitizeInput($_POST['config_imap_password']);
|
||||
|
||||
// Shared OAuth fields
|
||||
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
|
||||
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
|
||||
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']);
|
||||
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
|
||||
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']);
|
||||
|
||||
mysqli_query($mysqli, "
|
||||
UPDATE settings SET
|
||||
config_imap_provider = '$config_imap_provider',
|
||||
config_imap_host = '$config_imap_host',
|
||||
config_imap_port = $config_imap_port,
|
||||
config_imap_encryption = '$config_imap_encryption',
|
||||
config_imap_username = '$config_imap_username',
|
||||
config_imap_password = '$config_imap_password',
|
||||
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
|
||||
config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
|
||||
config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
|
||||
config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
|
||||
config_mail_oauth_access_token = '$config_mail_oauth_access_token'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited IMAP settings");
|
||||
|
||||
flash_alert("IMAP Mail Settings updated");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_from_settings'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_mail_from_email = sanitizeInput(filter_var($_POST['config_mail_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_mail_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_mail_from_name']));
|
||||
|
||||
$config_invoice_from_email = sanitizeInput(filter_var($_POST['config_invoice_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_invoice_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_invoice_from_name']));
|
||||
|
||||
$config_quote_from_email = sanitizeInput(filter_var($_POST['config_quote_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_quote_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_quote_from_name']));
|
||||
|
||||
$config_ticket_from_email = sanitizeInput(filter_var($_POST['config_ticket_from_email'], FILTER_VALIDATE_EMAIL));
|
||||
$config_ticket_from_name = sanitizeInput(preg_replace('/[^a-zA-Z0-9\s]/', '', $_POST['config_ticket_from_name']));
|
||||
|
||||
mysqli_query($mysqli,"UPDATE settings SET config_mail_from_email = '$config_mail_from_email', config_mail_from_name = '$config_mail_from_name', config_invoice_from_email = '$config_invoice_from_email', config_invoice_from_name = '$config_invoice_from_name', config_quote_from_email = '$config_quote_from_email', config_quote_from_name = '$config_quote_from_name', config_ticket_from_email = '$config_ticket_from_email', config_ticket_from_name = '$config_ticket_from_name' WHERE company_id = 1");
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited mail from settings");
|
||||
|
||||
flash_alert("Mail From Settings updated");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['test_email_smtp'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$test_email = intval($_POST['test_email']);
|
||||
|
||||
if($test_email == 1) {
|
||||
$email_from = sanitizeInput($config_mail_from_email);
|
||||
$email_from_name = sanitizeInput($config_mail_from_name);
|
||||
} elseif ($test_email == 2) {
|
||||
$email_from = sanitizeInput($config_invoice_from_email);
|
||||
$email_from_name = sanitizeInput($config_invoice_from_name);
|
||||
} elseif ($test_email == 3) {
|
||||
$email_from = sanitizeInput($config_quote_from_email);
|
||||
$email_from_name = sanitizeInput($config_quote_from_name);
|
||||
} else {
|
||||
$email_from = sanitizeInput($config_ticket_from_email);
|
||||
$email_from_name = sanitizeInput($config_ticket_from_name);
|
||||
}
|
||||
|
||||
$email_to = sanitizeInput($_POST['email_to']);
|
||||
$subject = "Test email from ITFlow";
|
||||
$body = "This is a test email from ITFlow. If you are reading this, it worked!";
|
||||
|
||||
$data = [
|
||||
[
|
||||
'from' => $email_from,
|
||||
'from_name' => $email_from_name,
|
||||
'recipient' => $email_to,
|
||||
'recipient_name' => 'Chap',
|
||||
'subject' => $subject,
|
||||
'body' => $body
|
||||
]
|
||||
];
|
||||
|
||||
$mail = addToMailQueue($data);
|
||||
|
||||
if ($mail === true) {
|
||||
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');
|
||||
}
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['test_email_imap'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$provider = sanitizeInput($config_imap_provider ?? '');
|
||||
|
||||
$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;
|
||||
|
||||
// Shared OAuth fields
|
||||
$config_mail_oauth_client_id = $config_mail_oauth_client_id ?? '';
|
||||
$config_mail_oauth_client_secret = $config_mail_oauth_client_secret ?? '';
|
||||
$config_mail_oauth_tenant_id = $config_mail_oauth_tenant_id ?? '';
|
||||
$config_mail_oauth_refresh_token = $config_mail_oauth_refresh_token ?? '';
|
||||
$config_mail_oauth_access_token = $config_mail_oauth_access_token ?? '';
|
||||
$config_mail_oauth_access_token_expires_at = $config_mail_oauth_access_token_expires_at ?? '';
|
||||
|
||||
$is_oauth = ($provider === 'google_oauth' || $provider === 'microsoft_oauth');
|
||||
|
||||
if ($provider === 'google_oauth') {
|
||||
if (empty($host)) {
|
||||
$host = 'imap.gmail.com';
|
||||
}
|
||||
if (empty($port)) {
|
||||
$port = 993;
|
||||
}
|
||||
if (empty($encryption)) {
|
||||
$encryption = 'ssl';
|
||||
}
|
||||
} elseif ($provider === 'microsoft_oauth') {
|
||||
if (empty($host)) {
|
||||
$host = 'outlook.office365.com';
|
||||
}
|
||||
if (empty($port)) {
|
||||
$port = 993;
|
||||
}
|
||||
if (empty($encryption)) {
|
||||
$encryption = 'ssl';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($host) || empty($port) || empty($username)) {
|
||||
flash_alert("<strong>IMAP connection failed:</strong> Missing host, port, or username.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$token_is_expired = function (?string $expires_at): bool {
|
||||
if (empty($expires_at)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ts = strtotime($expires_at);
|
||||
|
||||
if ($ts === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ($ts - 60) <= time();
|
||||
};
|
||||
|
||||
$http_form_post = function (string $url, array $fields): array {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
||||
|
||||
$raw = curl_exec($ch);
|
||||
$err = curl_error($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return [
|
||||
'ok' => ($raw !== false && $code >= 200 && $code < 300),
|
||||
'body' => $raw,
|
||||
'code' => $code,
|
||||
'err' => $err,
|
||||
];
|
||||
};
|
||||
|
||||
if ($is_oauth) {
|
||||
if (!empty($config_mail_oauth_access_token) && !$token_is_expired($config_mail_oauth_access_token_expires_at)) {
|
||||
$password = $config_mail_oauth_access_token;
|
||||
} else {
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_refresh_token)) {
|
||||
flash_alert("<strong>IMAP OAuth failed:</strong> Missing OAuth client credentials or refresh token.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
if ($provider === 'google_oauth') {
|
||||
$response = $http_form_post('https://oauth2.googleapis.com/token', [
|
||||
'client_id' => $config_mail_oauth_client_id,
|
||||
'client_secret' => $config_mail_oauth_client_secret,
|
||||
'refresh_token' => $config_mail_oauth_refresh_token,
|
||||
'grant_type' => 'refresh_token',
|
||||
]);
|
||||
} else {
|
||||
if (empty($config_mail_oauth_tenant_id)) {
|
||||
flash_alert("<strong>IMAP OAuth failed:</strong> Microsoft tenant ID is required.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$token_url = MICROSOFT_OAUTH_BASE_URL . rawurlencode($config_mail_oauth_tenant_id) . "/oauth2/v2.0/token";
|
||||
$response = $http_form_post($token_url, [
|
||||
'client_id' => $config_mail_oauth_client_id,
|
||||
'client_secret' => $config_mail_oauth_client_secret,
|
||||
'refresh_token' => $config_mail_oauth_refresh_token,
|
||||
'grant_type' => 'refresh_token',
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$response['ok']) {
|
||||
flash_alert("<strong>IMAP OAuth failed:</strong> Could not refresh access token.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$json = json_decode($response['body'], true);
|
||||
if (!is_array($json) || empty($json['access_token'])) {
|
||||
flash_alert("<strong>IMAP OAuth failed:</strong> Token response did not include an access token.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$password = $json['access_token'];
|
||||
$expires_at = date('Y-m-d H:i:s', time() + (int)($json['expires_in'] ?? 3600));
|
||||
$refresh_token_to_save = $json['refresh_token'] ?? null;
|
||||
|
||||
$token_esc = mysqli_real_escape_string($mysqli, $password);
|
||||
$expires_at_esc = mysqli_real_escape_string($mysqli, $expires_at);
|
||||
|
||||
$refresh_sql = '';
|
||||
if (!empty($refresh_token_to_save)) {
|
||||
$refresh_token_esc = mysqli_real_escape_string($mysqli, $refresh_token_to_save);
|
||||
$refresh_sql = ", config_mail_oauth_refresh_token = '{$refresh_token_esc}'";
|
||||
}
|
||||
|
||||
mysqli_query($mysqli, "UPDATE settings SET config_mail_oauth_access_token = '{$token_esc}', config_mail_oauth_access_token_expires_at = '{$expires_at_esc}'{$refresh_sql} WHERE company_id = 1");
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
$context_options = [];
|
||||
if (in_array($encryption, ['ssl', 'tls'], true)) {
|
||||
$context_options['ssl'] = [
|
||||
'verify_peer' => false,
|
||||
'verify_peer_name' => false,
|
||||
'allow_self_signed' => true,
|
||||
];
|
||||
}
|
||||
|
||||
$context = stream_context_create($context_options);
|
||||
|
||||
try {
|
||||
$errno = 0;
|
||||
$errstr = '';
|
||||
|
||||
// 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) {
|
||||
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));
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
$tag = 'A0002';
|
||||
|
||||
if ($is_oauth) {
|
||||
$oauth_b64 = base64_encode("user={$username}\x01auth=Bearer {$password}\x01\x01");
|
||||
$auth_cmd = sprintf("%s AUTHENTICATE XOAUTH2 %s\r\n", $tag, $oauth_b64);
|
||||
fwrite($fp, $auth_cmd);
|
||||
} else {
|
||||
$login_cmd = sprintf(
|
||||
"%s LOGIN \"%s\" \"%s\"\r\n",
|
||||
$tag,
|
||||
addcslashes($username, "\\\""),
|
||||
addcslashes($password, "\\\"")
|
||||
);
|
||||
|
||||
fwrite($fp, $login_cmd);
|
||||
}
|
||||
|
||||
$success = false;
|
||||
$error_line = '';
|
||||
|
||||
while (!feof($fp)) {
|
||||
$line = fgets($fp, 2048);
|
||||
if ($line === false) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strpos($line, $tag . ' ') === 0) {
|
||||
if (stripos($line, $tag . ' OK') === 0) {
|
||||
$success = true;
|
||||
} else {
|
||||
$error_line = trim($line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Always logout / close
|
||||
fwrite($fp, "A0003 LOGOUT\r\n");
|
||||
fclose($fp);
|
||||
|
||||
if ($success) {
|
||||
if ($is_oauth) {
|
||||
flash_alert("Connected successfully using OAuth");
|
||||
} else {
|
||||
flash_alert("Connected successfully");
|
||||
}
|
||||
} else {
|
||||
if (!$error_line) {
|
||||
$error_line = 'Unknown IMAP authentication error';
|
||||
}
|
||||
throw new Exception($error_line);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
flash_alert("<strong>IMAP connection failed:</strong> " . htmlspecialchars($e->getMessage()), 'error');
|
||||
}
|
||||
|
||||
redirect();
|
||||
}
|
||||
|
||||
|
||||
if (isset($_POST['test_oauth_token_refresh'])) {
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$provider = sanitizeInput($_POST['oauth_provider'] ?? '');
|
||||
|
||||
if ($provider !== 'google_oauth' && $provider !== 'microsoft_oauth') {
|
||||
flash_alert("OAuth token test failed: unsupported provider.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$oauth_client_id = sanitizeInput($config_mail_oauth_client_id ?? '');
|
||||
$oauth_client_secret = sanitizeInput($config_mail_oauth_client_secret ?? '');
|
||||
$oauth_tenant_id = sanitizeInput($config_mail_oauth_tenant_id ?? '');
|
||||
$oauth_refresh_token = sanitizeInput($config_mail_oauth_refresh_token ?? '');
|
||||
|
||||
if (empty($oauth_client_id) || empty($oauth_client_secret) || empty($oauth_refresh_token)) {
|
||||
flash_alert("OAuth token test failed: missing client ID, client secret, or refresh token.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
if ($provider === 'microsoft_oauth' && empty($oauth_tenant_id)) {
|
||||
flash_alert("OAuth token test failed: Microsoft tenant ID is required.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$token_url = 'https://oauth2.googleapis.com/token';
|
||||
if ($provider === 'microsoft_oauth') {
|
||||
$token_url = MICROSOFT_OAUTH_BASE_URL . rawurlencode($oauth_tenant_id) . "/oauth2/v2.0/token";
|
||||
}
|
||||
|
||||
$post_fields = http_build_query([
|
||||
'client_id' => $oauth_client_id,
|
||||
'client_secret' => $oauth_client_secret,
|
||||
'refresh_token' => $oauth_refresh_token,
|
||||
'grant_type' => 'refresh_token',
|
||||
]);
|
||||
|
||||
$ch = curl_init($token_url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
||||
|
||||
$raw_body = curl_exec($ch);
|
||||
$curl_err = curl_error($ch);
|
||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($raw_body === false || $http_code < 200 || $http_code >= 300) {
|
||||
$err_msg = !empty($curl_err) ? $curl_err : "HTTP $http_code";
|
||||
flash_alert("OAuth token test failed: $err_msg", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$json = json_decode($raw_body, true);
|
||||
|
||||
if (!is_array($json) || empty($json['access_token'])) {
|
||||
flash_alert("OAuth token test failed: access token missing in provider response.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$new_access_token = sanitizeInput($json['access_token']);
|
||||
$new_expires_at = date('Y-m-d H:i:s', time() + (int)($json['expires_in'] ?? 3600));
|
||||
$new_refresh_token = !empty($json['refresh_token']) ? sanitizeInput($json['refresh_token']) : '';
|
||||
|
||||
$new_access_token_esc = mysqli_real_escape_string($mysqli, $new_access_token);
|
||||
$new_expires_at_esc = mysqli_real_escape_string($mysqli, $new_expires_at);
|
||||
|
||||
$refresh_sql = '';
|
||||
if (!empty($new_refresh_token)) {
|
||||
$new_refresh_token_esc = mysqli_real_escape_string($mysqli, $new_refresh_token);
|
||||
$refresh_sql = ", config_mail_oauth_refresh_token = '$new_refresh_token_esc'";
|
||||
}
|
||||
|
||||
mysqli_query($mysqli, "UPDATE settings SET config_mail_oauth_access_token = '$new_access_token_esc', config_mail_oauth_access_token_expires_at = '$new_expires_at_esc'$refresh_sql WHERE company_id = 1");
|
||||
|
||||
$provider_label = $provider === 'microsoft_oauth' ? 'Microsoft 365' : 'Google Workspace';
|
||||
logAction("Settings", "Edit", "$session_name tested OAuth token refresh for $provider_label mail settings");
|
||||
|
||||
flash_alert("OAuth token refresh successful for $provider_label. Access token expires at $new_expires_at.");
|
||||
redirect();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
if (isset($_GET['stripe_remove_pm'])) {
|
||||
|
||||
|
||||
validateCSRFToken($_GET['csrf_token']);
|
||||
|
||||
if (!$config_stripe_enable) {
|
||||
@@ -34,21 +34,21 @@ if (isset($_GET['stripe_remove_pm'])) {
|
||||
// Remove Auto Pay on recurring invoices that are stripe
|
||||
$sql_recurring_invoices = mysqli_query($mysqli, "SELECT recurring_invoice_id FROM recurring_invoices WHERE recurring_invoice_client_id = $client_id");
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_recurring_invoices)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_recurring_invoices)) {
|
||||
$recurring_invoice_id = intval($row['recurring_invoice_id']);
|
||||
mysqli_query($mysqli, "DELETE FROM recurring_payments WHERE recurring_payment_method = 'Stripe' AND recurring_payment_recurring_invoice_id = $recurring_invoice_id");
|
||||
}
|
||||
|
||||
logAction("Stripe", "Update", "$session_name deleted saved Stripe payment method (PM: $payment_method)", $client_id);
|
||||
|
||||
|
||||
flash_alert("Payment method removed", 'error');
|
||||
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['stripe_reset_customer'])) {
|
||||
|
||||
|
||||
validateCSRFToken($_GET['csrf_token']);
|
||||
|
||||
$client_id = intval($_GET['client_id']);
|
||||
@@ -59,7 +59,7 @@ if (isset($_GET['stripe_reset_customer'])) {
|
||||
// Remove Auto Pay on recurring invoices that are stripe
|
||||
$sql_recurring_invoices = mysqli_query($mysqli, "SELECT recurring_invoice_id FROM recurring_invoices WHERE recurring_invoice_client_id = $client_id");
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_recurring_invoices)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_recurring_invoices)) {
|
||||
$recurring_invoice_id = intval($row['recurring_invoice_id']);
|
||||
mysqli_query($mysqli, "DELETE FROM recurring_payments WHERE recurring_payment_method = 'Stripe' AND recurring_payment_recurring_invoice_id = $recurring_invoice_id");
|
||||
}
|
||||
@@ -67,7 +67,7 @@ if (isset($_GET['stripe_reset_customer'])) {
|
||||
logAction("Stripe", "Delete", "$session_name reset Stripe settings for client", $client_id);
|
||||
|
||||
flash_alert("Reset client Stripe settings", 'error');
|
||||
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ if (isset($_GET['delete_software_template'])) {
|
||||
|
||||
// Get Software Template Name for logging and alert message
|
||||
$sql = mysqli_query($mysqli,"SELECT software_template_name FROM software_templates WHERE software_template_id = $software_template_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$software_template_name = sanitizeInput($row['software_template_name']);
|
||||
|
||||
mysqli_query($mysqli,"DELETE FROM software_templates WHERE software_template_id = $software_template_id");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ if (isset($_GET['update'])) {
|
||||
if ($config_telemetry > 0 OR $config_telemetry = 2) {
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
|
||||
$company_name = sanitizeInput($row['company_name']);
|
||||
$website = sanitizeInput($row['company_website']);
|
||||
|
||||
@@ -53,7 +53,7 @@ if (isset($_POST['add_user'])) {
|
||||
mysqli_query($mysqli, "INSERT INTO user_settings SET user_id = $user_id, user_config_force_mfa = $force_mfa");
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$company_name = sanitizeInput($row['company_name']);
|
||||
|
||||
// Sanitize Config vars from load_global_settings.php
|
||||
@@ -118,7 +118,7 @@ if (isset($_POST['edit_user'])) {
|
||||
|
||||
// Get current Avatar
|
||||
$sql = mysqli_query($mysqli, "SELECT user_avatar FROM users WHERE user_id = $user_id");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$existing_file_name = sanitizeInput($row['user_avatar']);
|
||||
|
||||
$extended_log_description = '';
|
||||
@@ -148,7 +148,7 @@ if (isset($_POST['edit_user'])) {
|
||||
// Set Avatar
|
||||
mysqli_query($mysqli, "UPDATE users SET user_avatar = '$new_file_name' WHERE user_id = $user_id");
|
||||
$extended_alert_description = '. File successfully uploaded.';
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,8 +353,8 @@ if (isset($_POST['ir_reset_user_password'])) {
|
||||
// Confirm logged-in user password, for security
|
||||
$admin_password = $_POST['admin_password'];
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_id = $session_user_id");
|
||||
$userRow = mysqli_fetch_array($sql);
|
||||
|
||||
$userRow = mysqli_fetch_assoc($sql);
|
||||
|
||||
if (!password_verify($admin_password, $userRow['user_password'])) {
|
||||
flash_alert("Incorrect password.", 'error');
|
||||
redirect();
|
||||
@@ -364,7 +364,7 @@ if (isset($_POST['ir_reset_user_password'])) {
|
||||
$sql_users = mysqli_query($mysqli, "SELECT * FROM users WHERE (user_archived_at IS NULL AND user_id != $session_user_id)");
|
||||
|
||||
// Reset passwords
|
||||
while ($row = mysqli_fetch_array($sql_users)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_users)) {
|
||||
$user_id = intval($row['user_id']);
|
||||
$user_email = sanitizeInput($row['user_email']);
|
||||
$new_password = randomString();
|
||||
|
||||
@@ -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">
|
||||
@@ -61,7 +61,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while($row = mysqli_fetch_array($sql)){
|
||||
while($row = mysqli_fetch_assoc($sql)){
|
||||
$project_template_id = intval($row['project_template_id']);
|
||||
$project_template_name = nullable_htmlentities($row['project_template_name']);
|
||||
$project_template_description = nullable_htmlentities($row['project_template_description']);
|
||||
@@ -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,9 +123,7 @@ $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";
|
||||
|
||||
@@ -13,13 +13,13 @@ 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;
|
||||
}
|
||||
|
||||
$row = mysqli_fetch_array($sql_project_templates);
|
||||
$row = mysqli_fetch_assoc($sql_project_templates);
|
||||
|
||||
$project_template_name = nullable_htmlentities($row['project_template_name']);
|
||||
$project_template_description = nullable_htmlentities($row['project_template_description']);
|
||||
@@ -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) { ?>
|
||||
@@ -143,7 +143,7 @@ if (isset($_GET['project_template_id'])) {
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_ticket_templates)) {
|
||||
while ($row = mysqli_fetch_assoc($sql_ticket_templates)) {
|
||||
$ticket_template_id = intval($row['ticket_template_id']);
|
||||
$ticket_template_order = intval($row['ticket_template_order']);
|
||||
$ticket_template_name = nullable_htmlentities($row['ticket_template_name']);
|
||||
@@ -199,7 +199,7 @@ if (isset($_GET['project_template_id'])) {
|
||||
<h5 class="text-secondary"><i class="fas fa-fw fa-tasks mr-2"></i>Project Task Templates</h5>
|
||||
<table class="table">
|
||||
<?php
|
||||
while($row = mysqli_fetch_array($sql_task_templates)){
|
||||
while($row = mysqli_fetch_assoc($sql_task_templates)){
|
||||
$task_template_id = intval($row['task_template_id']);
|
||||
$task_template_name = nullable_htmlentities($row['task_template_name']);
|
||||
?>
|
||||
@@ -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";
|
||||
|
||||
@@ -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>
|
||||
@@ -65,7 +65,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$role_id = intval($row['role_id']);
|
||||
$role_name = nullable_htmlentities($row['role_name']);
|
||||
$role_description = nullable_htmlentities($row['role_description']);
|
||||
@@ -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";
|
||||
|
||||
@@ -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>
|
||||
@@ -94,7 +104,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$saved_payment_id = intval($row['saved_payment_id']);
|
||||
$client_id = intval($row['saved_payment_client_id']);
|
||||
$client_name = nullable_htmlentities($row['client_name']);
|
||||
@@ -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>
|
||||
|
||||
@@ -4,7 +4,7 @@ require_once "includes/inc_all_admin.php";
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$company_id = intval($row['company_id']);
|
||||
$company_name = nullable_htmlentities($row['company_name']);
|
||||
$company_country = nullable_htmlentities($row['company_country']);
|
||||
|
||||
@@ -66,13 +66,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$custom_field_id = intval($row['custom_field_id']);
|
||||
$custom_field_label = nullable_htmlentities($row['custom_field_label']);
|
||||
$custom_field_type = nullable_htmlentities($row['custom_field_type']);
|
||||
$custom_field_location = intval($row['custom_field_location']);
|
||||
$custom_field_order = intval($row['custom_field_order']);
|
||||
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td><a class="text-dark" href="#" data-toggle="modal" data-target="#editCustomFieldModal<?php echo $custom_field_id; ?>"><?php echo $custom_field_label; ?></a></td>
|
||||
@@ -118,4 +118,3 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
require_once "custom_field_create_modal.php";
|
||||
|
||||
require_once "../includes/footer.php";
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM calendars ORDER BY calendar_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$calendar_id = intval($row['calendar_id']);
|
||||
$calendar_name = nullable_htmlentities($row['calendar_name']); ?>
|
||||
<option <?php if ($config_default_calendar == $calendar_id) {
|
||||
@@ -65,7 +65,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$account_id = intval($row['account_id']);
|
||||
$account_name = nullable_htmlentities($row['account_name']); ?>
|
||||
<option <?php if ($config_default_transfer_from_account == $account_id) {
|
||||
@@ -88,7 +88,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$account_id = intval($row['account_id']);
|
||||
$account_name = nullable_htmlentities($row['account_name']); ?>
|
||||
<option <?php if ($config_default_transfer_to_account == $account_id) {
|
||||
@@ -111,7 +111,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$account_id = intval($row['account_id']);
|
||||
$account_name = nullable_htmlentities($row['account_name']); ?>
|
||||
<option <?php if ($config_default_payment_account == $account_id) {
|
||||
@@ -136,7 +136,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM accounts WHERE account_archived_at IS NULL ORDER BY account_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$account_id = intval($row['account_id']);
|
||||
$account_name = nullable_htmlentities($row['account_name']); ?>
|
||||
<option <?php if ($config_default_expense_account == $account_id) {
|
||||
@@ -159,7 +159,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Payment Method' ORDER BY category_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$payment_method = nullable_htmlentities($row['category_name']); ?>
|
||||
<option <?php if ($config_default_payment_method == $payment_method) {
|
||||
echo "selected";
|
||||
@@ -181,7 +181,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Payment Method' ORDER BY category_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$payment_method = nullable_htmlentities($row['category_name']); ?>
|
||||
<option <?php if ($config_default_expense_payment_method == $payment_method) {
|
||||
echo "selected";
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ require_once "includes/inc_all_admin.php";
|
||||
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$company_locale = nullable_htmlentities($row['company_locale']);
|
||||
$company_currency = nullable_htmlentities($row['company_currency']);
|
||||
|
||||
@@ -76,4 +76,3 @@ $timezones = DateTimeZone::listIdentifiers();
|
||||
|
||||
<?php
|
||||
require_once "../includes/footer.php";
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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";
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ require_once "includes/inc_all_admin.php";
|
||||
<label>Kanban Settings</label>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" name="config_ticket_ordering" <?php if ($config_ticket_ordering == 1) { echo "checked"; } ?> value="1" id="ticketOrderingSwitch">
|
||||
<label class="custom-control-label" for="ticketOrderingSwitch">Allow ticket ordering within its column<small class="text-secondary">(uncheked will result in ordering it by priority and id)</small></label>
|
||||
<label class="custom-control-label" for="ticketOrderingSwitch">Allow ticket ordering within its column<small class="text-secondary"> (unchecked = order by priority and id)</small></label>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" name="config_ticket_moving_columns" <?php if ($config_ticket_moving_columns == 1) { echo "checked"; } ?> value="1" id="ticketMovingColumnsSwitch">
|
||||
|
||||
@@ -9,7 +9,7 @@ require_once "includes/inc_all_admin.php";
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM software_templates
|
||||
WHERE software_template_name LIKE '%$q%' OR software_template_type LIKE '%$q%'
|
||||
WHERE software_template_name LIKE '%$q%' OR software_template_type LIKE '%$q%'
|
||||
ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
@@ -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">
|
||||
@@ -68,7 +68,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while($row = mysqli_fetch_array($sql)){
|
||||
while($row = mysqli_fetch_assoc($sql)){
|
||||
$software_template_id = intval($row['software_template_id']);
|
||||
$software_template_name = nullable_htmlentities($row['software_template_name']);
|
||||
$software_template_version = nullable_htmlentities($row['software_template_version']);
|
||||
@@ -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";
|
||||
|
||||
@@ -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,32 +111,15 @@ $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>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($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>
|
||||
|
||||
|
||||
151
admin/tax.php
151
admin/tax.php
@@ -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_assoc($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";
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -67,7 +67,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_assoc($sql)) {
|
||||
$ticket_status_id = intval($row['ticket_status_id']);
|
||||
$ticket_status_name = nullable_htmlentities($row['ticket_status_name']);
|
||||
$ticket_status_color = nullable_htmlentities($row['ticket_status_color']);
|
||||
@@ -81,7 +81,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="#"
|
||||
<a href="#"
|
||||
<?php if ( $ticket_status_id > 5 ) { ?>
|
||||
class="ajax-modal" data-modal-url="modals/ticket_status/ticket_status_edit.php?id=<?= $ticket_status_id ?>"
|
||||
<?php } ?>
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@ require_once "includes/inc_all_admin.php";
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS *,
|
||||
"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
|
||||
ORDER BY $sort $order
|
||||
LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
@@ -27,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">
|
||||
@@ -69,7 +69,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while($row = mysqli_fetch_array($sql)){
|
||||
while($row = mysqli_fetch_assoc($sql)){
|
||||
$ticket_template_id = intval($row['ticket_template_id']);
|
||||
$ticket_template_name = nullable_htmlentities($row['ticket_template_name']);
|
||||
$ticket_template_description = nullable_htmlentities($row['ticket_template_description']);
|
||||
@@ -120,5 +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";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user