Compare commits

..

116 Commits

Author SHA1 Message Date
rodude123 00851d37b8 Merge pull request 'Fixed small tiny issue with the carousel having less the maximum number of visible items i.e. none in the hidden div' (#57) from older-blog-posts-fix into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
Reviewed-on: #57
2024-11-04 22:39:51 +00:00
rodude123 a55ba6ce2f Fixed small tiny issue with the carousel having less the maximum number of visible items i.e. none in the hidden div
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 20s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-11-04 22:39:04 +00:00
rodude123 c2e01dd1e8 Merge pull request 'older-blog-posts' (#56) from older-blog-posts into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 18s
Reviewed-on: #56
2024-11-04 22:30:01 +00:00
rodude123 860c52e829 Removed commented code from blogData.php
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-11-04 22:28:23 +00:00
rodude123 b28e7b2da5 Various fixes for the blog and editor. As well as finally adding in the carousel!
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 24s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-11-04 22:17:42 +00:00
rodude123 7d6eeb2310 Merge pull request 'various-fixes' (#55) from various-fixes into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 20s
Reviewed-on: #55
2024-06-22 19:02:57 +01:00
rodude123 558ac03fbb various fixes for the blog including prismjs highlighting, colour schemes and embedding media
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 25s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-06-22 17:46:17 +01:00
rodude123 646cfa6561 various fixes for the blog including prismjs highlighting, colour schemes and embedding media
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 23s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-02-11 23:13:58 +00:00
rodude123 591db4dfa3 Uncommented the code, shouldn't have been commented in the first place
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 30s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-01-01 19:09:23 +00:00
rodude123 7f96aa9277 Merge pull request 'Impleted SAML SSO' (#54) from SAML-auth into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 28s
Reviewed-on: #54
2024-01-01 13:55:12 +00:00
rodude123 7b8e81e1f7 Added SAML-Toolkits php-saml to composer and installed it to the vendor folder. Implemented SSO with JumpCloud
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 31s
Signed-off-by: rodude123 <rodude123@gmail.com>
2024-01-01 13:52:30 +00:00
rodude123 430e1c65ca Merge pull request 'fixed main url' (#53) from url-fix into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 33s
Reviewed-on: #53
2023-12-28 18:04:59 +00:00
rodude123 364e2d2675 fixed main url
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
2023-12-13 15:39:39 +00:00
rodude123 804d8a9390 Merge pull request 'Fixed some bugs in the newsletter images, made some minor improvements in other areas. Added in unsubscribe functionality' (#52) from bug-fixes-and-unsubscribe into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
Reviewed-on: #52
2023-12-13 03:11:40 +00:00
rodude123 a5f17a70ed Fixed some bugs in the newsletter images, made some minor improvements in other areas. Added in unsubscribe functionality
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 21s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-12-13 03:10:23 +00:00
rodude123 62f871f4ca Merge pull request 'newsletter-and-cookies' (#51) from newsletter-and-cookies into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
Reviewed-on: #51
2023-12-06 23:32:09 +00:00
rodude123 0cb57d0813 Made cookie popup work for most browsers
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-12-06 23:30:25 +00:00
rodude123 52614e5835 Added in a cookie popup and proper newsletter functionality
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 21s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-12-06 00:38:33 +00:00
rodude123 e6522fb05e Merge pull request 'feed-and-misc' (#50) from feed-and-misc into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 18s
Reviewed-on: #50
2023-11-18 13:14:08 +00:00
rodude123 5b063afad3 Got keywords from text using rake-php-plus and then stored in the DB, then used it to append the keywords to the meta tag.
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 20s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-11-18 13:06:27 +00:00
rodude123 f27a5113b1 Created feeds and UI for feeds and newsletter
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-11-14 01:03:17 +00:00
rodude123 6cfea3fc98 Merge pull request 'fixed mobile view of menubar, search page and category page' (#49) from search-fix into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 18s
Reviewed-on: #49
2023-11-08 22:24:43 +00:00
rodude123 d8a7901574 fixed mobile view of menubar, search page and category page
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 0s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-11-06 19:37:26 +00:00
rodude123 f3f68717ee Merge pull request 'Search' (#48) from search into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
Reviewed-on: #48
2023-11-05 17:50:00 +00:00
rodude123 f54ed2f8fb added frontend search functionality with a small menubar
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 23s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-11-05 17:47:44 +00:00
rodude123 b4ab7900db added backend search functionality
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-10-31 19:36:51 +00:00
rodude123 929060ce70 Merge pull request 'mobile-friendly-blog' (#47) from mobile-friendly-blog into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
Reviewed-on: #47
2023-10-28 19:02:34 +01:00
rodude123 03f14ba174 Completed mobile view and changed some minor things
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 19s
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-10-28 19:01:14 +01:00
rodude123 801e336c29 added comments
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
2023-10-28 13:14:59 +01:00
rodude123 d3a8ff927c changed width of the main content
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
2023-10-28 12:17:30 +01:00
rodude123 5878dbaf9a Merge pull request 'categories-fix' (#46) from categories-fix into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
Reviewed-on: #46
2023-10-28 11:29:42 +01:00
rodude123 edabd92c17 fixed css errors
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 19s
2023-10-28 11:26:39 +01:00
rodude123 730b822a2b centered button in container
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
2023-10-24 17:58:18 +01:00
rodude123 9e94f6cade added bottom margin
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 46s
2023-10-24 16:25:32 +01:00
rodude123 a868136a99 margin centered
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
2023-10-24 16:22:16 +01:00
rodude123 fbf9449116 set width to 100%
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
2023-10-24 16:20:35 +01:00
rodude123 9349f73016 centered items
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
2023-10-24 16:19:11 +01:00
rodude123 b06614a8c7 fixed category page
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
2023-10-24 16:17:30 +01:00
rodude123 3db2520339 Merge pull request 'node-fix' (#45) from node-fix into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 17s
Reviewed-on: #45
2023-10-24 16:14:31 +01:00
rodude123 4c871c20a0 chnaged to run all branches
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
2023-10-24 16:08:02 +01:00
rodude123 3812f99259 changed node version
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 22s
2023-10-24 16:04:17 +01:00
rodude123 a697ea2ac8 Merge pull request 'categories-page' (#44) from categories-page into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
Reviewed-on: #44
2023-10-24 15:54:20 +01:00
rodude123 e106f89dcb All categories page created with flex
🚀 Deploy website on push / 🎉 Deploy (push) Has been cancelled
2023-10-21 23:26:00 +01:00
rodude123 da791c8866 Started work on all categories page
🚀 Deploy website on push / 🎉 Deploy (push) Has been cancelled
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-10-21 09:06:03 +01:00
rodude123 cdead14bfd Merge pull request 'workflow-fix' (#43) from workflow-fix into master
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 16s
Reviewed-on: #43
2023-10-20 10:40:32 +01:00
rodude123 1b39c58f76 Updated ftp worflow
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 25s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:23:31 +01:00
rodude123 aa00c7d21f Gitea actions test
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 15s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:21:33 +01:00
rodude123 c9c662c987 Updated ftp worflow
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 15s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:07:57 +01:00
rodude123 8a01cc5fb5 Updated ftp worflow to use correct versioning
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 4s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:07:07 +01:00
rodude123 f90ae7dbec Updated ftp worflow to fix password issue
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 3s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:06:05 +01:00
rodude123 2cf281bce6 Updated ftp worflow
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 16s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:03:46 +01:00
rodude123 f3091582f4 Updated ftp worflow
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 10:02:49 +01:00
rodude123 7bbfbe7905 Updated ftp worflow to newer version of the original workflow
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 16s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:57:49 +01:00
rodude123 e2b13cf0e3 Updated ftp worflow to use node latest as lts didn't work
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 16s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:50:58 +01:00
rodude123 d6254edc9c Updated ftp worflow
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 35s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:48:59 +01:00
rodude123 f3ed313b50 Updated ftp worflow to use node LTS
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 0s
2023-10-20 09:47:53 +01:00
rodude123 46a01c471f Updated ftp worflow to fix directory issue
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 27s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:40:16 +01:00
rodude123 20456dd644 Updated ftp worflow to use another actions as a test
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 34s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:38:05 +01:00
rodude123 2cb1b30439 Updated ftp worflow
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 28s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:34:31 +01:00
rodude123 4fc08c05e5 Updated ftp worflow
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 26s
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 09:32:07 +01:00
rodude123 28c9edc090 swtiched to different ftp deploy action
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 26s
2023-10-20 01:00:55 +01:00
rodude123 f87409c604 Updated workflow to fit gitea secret format
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 1m8s
2023-10-20 00:42:32 +01:00
rodude123 afd7578ca6 Updated workflow to fit gitea
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 41s
2023-10-20 00:39:16 +01:00
rodude123 69f6108ff4 Updated workflow for testing purposes
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 31s
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Signed-off-by: Rohit Pai <rodude123@cloud.rohitpai.co.uk>
2023-10-20 00:05:16 +01:00
rodude123 e3c45c43f2 Merge pull request 'Gitea actions test' (#42) from actions-patch into master
🚀 Deploy website on push / 🎉 Deploy (push) Failing after 29s
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Reviewed-on: #42
2023-10-19 13:34:08 +01:00
rodude123 63edde17a3 Gitea actions test
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2023-10-19 13:33:58 +01:00
rodude123 e8c97712d6 Merge pull request 'Gitea actions test' (#41) from actions-patch into master
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 2s
Reviewed-on: #41
2023-10-19 13:32:29 +01:00
rodude123 398a190839 Gitea actions test
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2023-10-19 13:32:15 +01:00
rodude123 6891ce11de Merge pull request 'Gitea actions test' (#40) from actions-test into master
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Reviewed-on: #40
2023-10-19 13:31:13 +01:00
rodude123 df0c7e7083 Gitea actions test
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
2023-10-19 13:29:44 +01:00
rodude123 f2ab40f03a Merge pull request 'Update actions to test if gitea actions works' (#39) from actions-test into master
Reviewed-on: #39
2023-10-19 13:25:51 +01:00
rodude123 966647ef0d Update actions to test if gitea actions works 2023-10-19 13:24:56 +01:00
rodude123 a0567a25f5 Created individual categories page
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-10-18 23:58:21 +01:00
rodude123 41745e3c13 Merge pull request 'Created Blog Post Page' (#38) from blog-post-page into master
Reviewed-on: #38
2023-10-18 00:30:50 +01:00
rodude123 57aa831cdf Created blog post page and updated a few things here and there to work with the blog post page. Has comments and a sidebar.
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-10-18 00:28:34 +01:00
rodude123 74d1ea35c1 Merge pull request 'Updated CKEditor config' (#37) from editor-fixes into master
Reviewed-on: #37
2023-08-17 20:20:00 +01:00
rodude123 4a503169de Updated CKEditor config to support styles and code block from
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-08-17 19:59:48 +01:00
rodude123 24dfe885bd Merge pull request 'edit-delete-post' (#36) from edit-delete-post into master
Reviewed-on: #36
2023-07-12 03:39:51 +01:00
rodude123 65bfe759b7 changed e to _ as e was not used
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-07-12 03:30:45 +01:00
rodude123 3b71ba4d23 Added the ability to edit and delete posts which includes uploading of images for the posts and managing those images
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-07-12 03:29:56 +01:00
rodude123 be5e047f51 Merge pull request 'project-data-fix' (#35) from project-data-fix into master
Reviewed-on: #35
2023-06-26 18:13:40 +01:00
rodude123 e4877453cc Added where statements to is main project queries
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-26 18:11:43 +01:00
rodude123 7d0317ed60 Fixed small issues with projectData not being able to save uploaded image url to db
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-26 18:08:53 +01:00
rodude123 5ac8282fb6 Merge pull request 'add-to-blog' (#34) from add-to-blog into master
Reviewed-on: #34
2023-06-26 17:05:57 +01:00
rodude123 7b637dac7b Added in the ability not upload a headerImage and instead use a placeholder. Folder ID is now stored in the DB
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-26 16:52:48 +01:00
rodude123 bae523b62b Uploaded imgUtils.php file
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-26 03:56:48 +01:00
rodude123 61b8d3a987 Used CKEditor for being able to edit the post body. Added the ability to make a post and send it to the backend. Formatted post on backend by moving images into respective directory with the post name and unique ID. Showed message if errored or succeeded.
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-26 03:54:25 +01:00
rodude123 88c5cc9508 Merge pull request 'intial-blog-setup' (#33) from intial-blog-setup into master
Reviewed-on: #33
2023-06-09 14:56:34 +01:00
rodude123 e82ec15504 Fixed bugs in blog routes and added doc comments to all route files
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-09 14:50:20 +01:00
rodude123 e339204bd7 Updated CV pdf
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-09 14:39:28 +01:00
rodude123 a3eb4678f9 Moved all current routes to individual folders which use a class system and inherit from an interface. Moved rest of the files for a better structure and for readability. Each editable cms should have its own folder with a routes class file and data class file
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-08 15:10:27 +01:00
rodude123 fb75dd2255 Changed to using here multiline strings instead
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-06 16:16:13 +01:00
rodude123 3ccc7de5b4 Setup initial backend for the blog posts and added in the link to the pages
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-06 16:04:39 +01:00
rodude123 23f7ff4dc5 added some base code for the blog page nothing fancy
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-06-03 14:09:23 +01:00
rodude123 4bacef2130 Merge pull request 'final-fixes' (#32) from final-fixes into master
Reviewed-on: #32
2023-03-05 20:00:52 +00:00
rodude123 df61b0be85 Final fixes to the website which should have been committed in the previous branch :(
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-03-05 19:41:02 +00:00
rodude123 2394f9691e Final fixes to the website which should have been committed in the previous branch :(
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-25 20:17:09 +00:00
rodude123 b3b0401420 Merge pull request 'final-touches-and-viewmore' (#31) from final-touches-and-viewmore into master
Reviewed-on: #31
2023-02-24 02:18:57 +00:00
rodude123 d4cc915524 Fixed mobile view of pages on projects page
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-24 02:15:20 +00:00
rodude123 048dc0b58b changed how a few code snippets work and added in all projects section to view all the current projects includig <div class="grid__item"></div>
<div class="grid__item"></div>
                                                                                                                   <div class="grid__item"></div>
                                                                                                                   <div class="grid__item"></div>the one as the main

Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-23 18:53:28 +00:00
rodude123 a85073b051 Merge pull request 'editor-projects' (#29) from editor-projects into master
Reviewed-on: #29
2023-02-07 03:35:44 +00:00
rodude123 16b51fdda8 Merged in master changes e.g. the auto year updates
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-07 03:35:07 +00:00
rodude123 2c612e5776 Added in ability to add a new project with and with an image and update a project with and without image. If a project is the main project then it cannot be deleted and when a new main project is selected it gets moved to the top.
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-07 03:09:14 +00:00
rodude123 fd64eb92b0 Added in ability to add a new project with and without an image
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-06 01:26:35 +00:00
rodude123 db7c12857e Added in ability to edit the project data item, although backend is not completed yet.
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-02-03 01:20:55 +00:00
rodude123 cef7cc5e64 Base HTML for projects section completed
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-01-17 01:56:03 +00:00
rodude123 51e3d88924 Merge pull request 'auto-update-year' (#28) from auto-update-year into master
Reviewed-on: #28
2023-01-16 05:11:02 +00:00
rodude123 8ac02d864f auto-update-year
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-01-16 05:01:14 +00:00
rodude123 69c3462a3d created acd for editing projects data
Signed-off-by: rodude123 <rodude123@gmail.com>
2022-11-11 14:04:43 +00:00
rodude123 4f01ebe6ce created acd for editing projects data
Signed-off-by: rodude123 <rodude123@gmail.com>
2022-11-11 13:56:42 +00:00
rodude123 1c1acfe938 Merge pull request 'Fixed login error where no error message was shown, now it does' (#27) from login-error-fix into master
Reviewed-on: #27
2022-11-01 14:15:32 +00:00
rodude123 eeb8c5b80f Fixed login error where no error message was shown, now it does
Signed-off-by: rodude123 <rodude123@gmail.com>
2022-11-01 04:59:39 +00:00
rodude123 485c1e27c3 Merge pull request 'editor-cv' (#26) from editor-cv into master
Reviewed-on: #26
2022-11-01 04:49:39 +00:00
rodude123 3dd5372e1c Being able to edit a timeline item fully working as currently tested.
Signed-off-by: rodude123 <rodude123@gmail.com>
2022-10-29 19:31:34 +01:00
rodude123 7b04af165e Being able to edit a timeline item fully working as currently tested.
Signed-off-by: rodude123 <rodude123@gmail.com>
2022-10-09 23:32:50 +01:00
rodude123 a5c7d16991 Added the ability to see the timeline data in the editor and added in a basic form.
Signed-off-by: rodude123 <rodude123@gmail.com>
2022-10-09 16:02:07 +01:00
248 changed files with 18692 additions and 13411 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"editor.guides": []
}
+12 -9
View File
@@ -1,17 +1,20 @@
on: push on:
push:
branches:
- '*'
name: 🚀 Deploy website on push name: 🚀 Deploy website on push
jobs: jobs:
web-deploy: web-deploy:
name: 🎉 Deploy name: 🎉 Deploy
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- name: 🚚 Get latest code - name: 🚚 Get latest code
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Use Node.js 12 - name: Use Node.js Latest
uses: actions/setup-node@v2-beta uses: actions/setup-node@v3
with: with:
node-version: '12' node-version: 20
- name: 🔨Run Gulp - name: 🔨Run Gulp
run: | run: |
@@ -19,10 +22,10 @@ jobs:
npm install npm install
npm start npm start
- name: 📂 Sync files - name: 📂 Sync files to server
uses: SamKirkland/FTP-Deploy-Action@4.1.0 uses: SamKirkland/FTP-Deploy-Action@v4.3.4
with: with:
server: ftp.rohitpai.co.uk server: ftp.rohitpai.co.uk
username: u987021215.rodude123 username: u987021215.rodude123
password: ${{ secrets.ftp_password }} password: ${{ secrets.FTPPASSWORD }}
local-dir: ./dist/ local-dir: ./dist/
+3 -2
View File
@@ -75,5 +75,6 @@ fabric.properties
.env .env
vendor/* vendor/*
node_modules/* node_modules/*
src/api/config.php src/api/utils/config.php
dist/api/config.php dist/api/utils/config.php
dist/api/.htaccess
Binary file not shown.

After

Width:  |  Height:  |  Size: 752 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

+25 -13
View File
@@ -1,18 +1,30 @@
{ {
"require": { "require": {
"slim/slim-skeleton": "^4.3", "slim/slim-skeleton": "^4.3",
"ext-pdo": "*", "ext-pdo": "*",
"slim/psr7": "^1.4", "slim/psr7": "^1.4",
"nyholm/psr7": "^1.4", "nyholm/psr7": "^1.4",
"nyholm/psr7-server": "^1.0", "nyholm/psr7-server": "^1.0",
"guzzlehttp/psr7": "^2.0", "guzzlehttp/psr7": "^2.0",
"http-interop/http-factory-guzzle": "^1.2", "http-interop/http-factory-guzzle": "^1.2",
"laminas/laminas-diactoros": "^2.6", "laminas/laminas-diactoros": "^2.6",
"laminas/laminas-httphandlerrunner": "^2.0", "laminas/laminas-httphandlerrunner": "^2.0",
"selective/samesite-cookie": "^0.3.0", "selective/samesite-cookie": "^0.3.0",
"ext-json": "*", "ext-json": "*",
"slim/slim": "^4.10", "slim/slim": "^4.10",
"rbdwllr/psr-jwt": "^2.0", "rbdwllr/psr-jwt": "^2.0",
"tuupola/slim-jwt-auth": "^3.6" "tuupola/slim-jwt-auth": "^3.6",
"ext-dom": "*",
"ext-libxml": "*",
"donatello-za/rake-php-plus": "^1.0",
"phpmailer/phpmailer": "^6.9",
"onelogin/php-saml": "^4.1",
"ext-mbstring": "*"
},
"repositories": [
{
"type": "composer",
"url": "https:\/\/www.phpclasses.org\/"
} }
]
} }
Generated
+415 -234
View File
File diff suppressed because it is too large Load Diff
+1529
View File
File diff suppressed because it is too large Load Diff
+436
View File
@@ -0,0 +1,436 @@
<?php
namespace api\blog;
require_once __DIR__ . "/../utils/routesInterface.php";
require_once "blogData.php";
use api\utils\routesInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
class blogRoutes implements routesInterface
{
private blogData $blogData;
/**
* constructor used to instantiate a base blog routes, to be used in the index.php file.
* @param App $app - the slim app used to create the routes
*/
public function __construct(App $app)
{
$this->blogData = new blogData();
$this->createRoutes($app);
}
/**
* creates the routes for the blog
* @param App $app - the slim app used to create the routes
* @return void - returns nothing
*/
public function createRoutes(App $app): void
{
$app->get("/blog/categories", function (Request $request, Response $response)
{
$post = $this->blogData->getCategories();
if (array_key_exists("errorMessage", $post))
{
$response->getBody()->write(json_encode($post));
return $response->withStatus(404);
}
$response->getBody()->write(json_encode($post));
return $response;
});
$app->get("/blog/categories/{category}", function (Request $request, Response $response, $args)
{
if ($args["category"] != null)
{
$post = $this->blogData->getPostsByCategory($args["category"]);
if (array_key_exists("errorMessage", $post))
{
$response->getBody()->write(json_encode($post));
return $response->withStatus(404);
}
$response->getBody()->write(json_encode($post));
return $response;
}
$response->getBody()->write(json_encode(array("error" => "Please provide a category")));
return $response->withStatus(400);
});
$app->get("/blog/post", function (Request $request, Response $response)
{
$posts = $this->blogData->getBlogPosts();
$json = json_encode($posts);
$response->getBody()->write($json);
if (array_key_exists("errorMessage", $posts))
{
$response->withStatus(404);
}
return $response;
});
$app->get("/blog/post/{type}", function (Request $request, Response $response, $args)
{
if ($args["type"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide a title")));
return $response->withStatus(400);
}
if ($args["type"] == "latest")
{
$post = $this->blogData->getLatestBlogPost();
if (array_key_exists("errorMessage", $post))
{
$response->getBody()->write(json_encode($post));
return $response->withStatus(404);
}
$response->getBody()->write(json_encode($post));
return $response;
}
if ($args["type"] == "featured")
{
$post = $this->blogData->getFeaturedBlogPost();
if (array_key_exists("errorMessage", $post))
{
$response->getBody()->write(json_encode($post));
return $response->withStatus(404);
}
$response->getBody()->write(json_encode($post));
return $response;
}
$post = $this->blogData->getBlogPost($args["type"]);
if (array_key_exists("errorMessage", $post))
{
$response->getBody()->write(json_encode($post));
return $response->withStatus(404);
}
$response->getBody()->write(json_encode($post));
return $response;
});
$app->get("/blog/feed/{type}", function (Request $request, Response $response, $args)
{
if ($args["type"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide a title")));
return $response->withStatus(400);
}
$feed = $this->blogData->getFeed($args["type"]);
if (is_array($feed))
{
$response->getBody()->write(json_encode($feed));
return $response->withStatus(404);
}
if ($args["type"] == "atom")
{
$response->getBody()->write($feed);
return $response->withHeader("Content-Type", "application/atom+xml");
}
if ($args["type"] == "rss")
{
$response->getBody()->write($feed);
return $response->withHeader("Content-Type", "application/rss+xml");
}
if ($args["type"] == "json")
{
$response->getBody()->write(json_encode($feed));
return $response->withHeader("Content-Type", "application/feed+json");
}
$response->getBody()->write(json_encode(array("error" => "Invalid feed type")));
return $response->withStatus(400);
});
$app->get("/blog/search/{searchTerm}", function (Request $request, $response, $args)
{
if ($args["searchTerm"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide a search term")));
return $response->withStatus(400);
}
$posts = $this->blogData->searchBlog($args["searchTerm"]);
$json = json_encode($posts);
$response->getBody()->write($json);
if (array_key_exists("errorMessage", $posts))
{
$response->withStatus(404);
}
return $response;
});
$app->patch("/blog/post/{id}", function (Request $request, Response $response, $args)
{
$data = $request->getParsedBody();
if ($args["id"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an ID")));
return $response->withStatus(400);
}
if (empty($data["title"]) || strlen($data["featured"]) == 0 || empty($data["body"]) || empty($data["bodyText"]) || empty($data["dateModified"]) || empty($data["categories"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
if (!preg_match('/[a-zA-Z0-9 ]+, |\w+/mx', $data["categories"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Categories must be in a CSV format")));
return $response->withStatus(400);
}
$message = $this->blogData->updatePost($args["id"], $data["title"], intval($data["featured"]), $data["abstract"], $data["body"], $data["bodyText"], $data["dateModified"], $data["categories"]);
if ($message === "post not found")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Error, post not found")));
return $response->withStatus(404);
}
if ($message === "unset featured")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Error, cannot unset featured post, try updating another post to be featured first")));
return $response->withStatus(409);
}
if (!is_bool($message) || $message === false)
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => $message)));
return $response->withStatus(500);
}
$response->withStatus(201);
return $response;
});
$app->delete("/blog/post/{id}", function (Request $request, Response $response, $args)
{
if ($args["id"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an ID")));
return $response->withStatus(400);
}
$message = $this->blogData->deletePost($args["id"]);
if ($message === "post not found")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Error, post not found")));
return $response->withStatus(404);
}
if ($message === "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Error, something went wrong")));
return $response->withStatus(500);
}
if ($message === "cannot delete")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Error, cannot delete featured post")));
return $response->withStatus(409);
}
return $response;
});
$app->delete("/blog/newsletter/{email}", function (Request $request, Response $response, $args)
{
if ($args["email"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an email")));
return $response->withStatus(400);
}
$message = $this->blogData->deleteNewsletterEmail($args["email"]);
if ($message === "email not found")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("message" => "Woah, you're already trying to leave without signing up?")));
return $response->withStatus(404);
}
if ($message === "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("message" => "Error, something went wrong")));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("message" => "Sorry to see you go! You'll no longer receive any emails from me. If you change your mind, you can always sign up again.")));
return $response;
});
$app->post("/blog/post", function (Request $request, Response $response)
{
$data = $request->getParsedBody();
$files = $request->getUploadedFiles();
if (empty($data["title"]) || strlen($data["featured"]) == 0 || empty($data["body"]) || empty($data["bodyText"]) || empty($data["abstract"]) || empty($data["dateCreated"]) || empty($data["categories"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Error, empty data sent")));
return $response->withStatus(400);
}
if (!preg_match('/[a-zA-Z0-9 ]+, |\w+/mx', $data["categories"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Categories must be in a CSV format")));
return $response->withStatus(400);
}
if (array_key_exists("headerImg", $files))
{
$headerImg = $files["headerImg"];
}
if (empty($files["headerImg"]))
{
$headerImg = null;
}
// $featured = $data["featured"] === "true";
$insertedID = $this->blogData->createPost($data["title"], $data["abstract"], $data["body"], $data["bodyText"], $data["dateCreated"], intval($data["featured"]), $data["categories"], $headerImg);
if (!is_int($insertedID))
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => $insertedID)));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("ID" => $insertedID)));
return $response->withStatus(201);
});
$app->post("/blog/uploadPostImage", function (Request $request, Response $response)
{
$files = $request->getUploadedFiles();
if (empty($files))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => array("message" => "Error, empty data sent"))));
return $response->withStatus(400);
}
$message = $this->blogData->uploadPostImage($files["upload"]);
if (!is_array($message))
{
$response->getBody()->write(json_encode(array("error" => array("message" => $message))));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode($message));
return $response->withStatus(201);
});
$app->post("/blog/headerImage/{id}", function (Request $request, Response $response, $args)
{
$files = $request->getUploadedFiles();
if ($args["id"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an ID")));
return $response->withStatus(400);
}
if (empty($files))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Error, empty data sent")));
return $response->withStatus(400);
}
$message = $this->blogData->uploadHeaderImage($args["id"], $files["headerImg"]);
if (!is_array($message))
{
$response->getBody()->write(json_encode(array("error" => $message)));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode($message));
return $response->withStatus(201);
});
$app->post("/blog/newsletter", function (Request $request, Response $response)
{
$data = $request->getParsedBody();
if (empty($data["subject"]) || empty($data["message"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Error, empty data sent")));
return $response->withStatus(400);
}
$message = $this->blogData->sendNewsletter(strtolower($data["subject"]), $data["message"]);
if (is_array($message))
{
$response->getBody()->write(json_encode(array("error" => "Error, something went wrong")));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("message" => "Message sent")));
return $response->withStatus(201);
});
$app->post("/blog/newsletter/{email}", function (Request $request, Response $response, $args)
{
if ($args["email"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an email")));
return $response->withStatus(400);
}
$message = $this->blogData->addNewsletterEmail($args["email"]);
if ($message === "Email already exists")
{
$response->getBody()->write(json_encode(array("message" => "exists")));
return $response->withStatus(409);
}
if (is_array($message) || !$message || $message === "error")
{
$response->getBody()->write(json_encode(array("message" => "Something went wrong")));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("message" => "Thanks for signing up!")));
return $response->withStatus(201);
});
}
}
+43 -213
View File
@@ -1,27 +1,25 @@
<?php /** @noinspection PhpIncludeInspection */ <?php
error_reporting(E_ALL);
session_start(); ini_set('display_errors', 1);
////////////////// Index file ////////////// ////////////////// Index file //////////////
/// Creates base routes and runs /// /// Creates base routes and runs ///
/// respective functions /// /// respective functions ///
//////////////////////////////////////////// ////////////////////////////////////////////
//require “routes.php”;
require "../vendor/autoload.php"; require "../vendor/autoload.php";
include "middleware.php"; require "utils/middleware.php";
include "timelineData.php"; require "timeline/timelineRoutes.php";
include "projectData.php"; require "project/projectRoutes.php";
include "user.php"; require "user/userRoutes.php";
require "blog/blogRoutes.php";
use api\middleware; use api\blog\blogRoutes;
use api\projectData; use api\project\projectRoutes;
use api\timelineData; use api\timeline\timelineRoutes;
use api\user; use api\user\userRoutes;
use api\utils\middleware;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Slim\Factory\AppFactory; use Slim\Factory\AppFactory;
use Tuupola\Middleware\JwtAuthentication;
// Start slim // Start slim
$app = AppFactory::create(); $app = AppFactory::create();
@@ -32,79 +30,40 @@ $app->setBasePath("/api");
// Add middleware // Add middleware
new middleware($app); new middleware($app);
$timelineData = new timelineData(); new timelineRoutes($app);
$projectData = new projectData(); new projectRoutes($app);
$user = new user(); new blogRoutes($app);
new userRoutes($app);
$app->get("/timelineData/{timeline}", function (Request $request, Response $response, array $args)
{
global $timelineData;
//check if route is available if it is get the data
//otherwise return an error
if($args["timeline"] == "edu")
{
$response->getBody()->write(json_encode($timelineData->getEduData()));
return $response;
}
if($args["timeline"] == "work")
{
$response->getBody()->write(json_encode($timelineData->getWorkData()));
return $response;
}
// something went wrong
$response->getBody()->write(json_encode(array("errorMessage" => "Error, timeline data not found")));
return $response->withStatus(404);
});
$app->get("/projectData", function (Request $request, Response $response)
{
global $projectData;
$result = $projectData->getProjectData();
$json = json_encode($result);
$response->getBody()->write($json);
if(array_key_exists("errorMessage", $result))
{
$response = $response->withStatus(404);
}
//use content type json to indicate json data on frontend.
return $response;
});
// misc routes
$app->post("/contact", function (Request $request, Response $response) $app->post("/contact", function (Request $request, Response $response)
{ {
$data = $request->getParsedBody(); $data = $request->getParsedBody();
if(empty($data["fName"]) || empty($data["lName"]) || empty($data["email"]) || empty($data["subject"]) || empty($data["message"])) if (empty($data["fName"]) || empty($data["lName"]) || empty($data["email"]) || empty($data["subject"]) || empty($data["message"]))
{ {
$response->getBody()->write(json_encode(array("errorMessage" => "Please fill out all the fields"))); $response->getBody()->write(json_encode(array("errorMessage" => "Please fill out all the fields")));
return $response->withStatus(400); return $response->withStatus(400);
} }
if (!filter_var($data["email"], FILTER_VALIDATE_EMAIL)) if (!filter_var($data["email"], FILTER_VALIDATE_EMAIL))
{ {
$response->getBody()->write(json_encode(array("errorMessage" => "Email is not the correct format"))); $response->getBody()->write(json_encode(array("errorMessage" => "Email is not the correct format")));
return $response->withStatus(400); return $response->withStatus(400);
} }
// email form filler/conatcter // email form filler/conatcter
$headers1 = "From: noreply@rohitpai.co.uk\r\n"; $headers1 = "From: noreply@rohitpai.co.uk\r\n";
$headers1 .= "Reply-To: rohit@rohitpai.co.uk\r\n"; $headers1 .= "Reply-To: rohit@rohitpai.co.uk\r\n";
$headers1 .= "MIME-Version: 1.0\r\n"; $headers1 .= "MIME-Version: 1.0\r\n";
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
$message1 = " $message1 = <<<HEREA
<html lang=\"en\"> <html lang="en">
<head> <head>
<title>{$data['subject']}</title> <title>{$data['subject']}</title>
<style> <style>
@import url(\"https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Share+Tech+Mono&family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap\"); @import url("https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Share+Tech+Mono&family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap");
body { body {
font-family: Noto Sans KR, sans-serif; font-family: Noto Sans KR, sans-serif;
font-style: normal; font-style: normal;
@@ -159,32 +118,32 @@ $app->post("/contact", function (Request $request, Response $response)
<tr> <tr>
<td>{$data['fName']}</td> <td>{$data['fName']}</td>
<td>{$data['lName']}</td> <td>{$data['lName']}</td>
<td><a href=\"mailto:{$data['email']}\">{$data['email']}</a></td> <td><a href="mailto:{$data['email']}">{$data['email']}</a></td>
<td>{$data['subject']}</td> <td>{$data['subject']}</td>
<td>{$data['message']}</td> <td>{$data['message']}</td>
</tr> </tr>
</table> </table>
<br> <br>
<hr> <hr>
<p>Regards, <br> Rohit Pai <br> <a href=\"mailto:rohit@rohitpai.co.uk\">rohit@rohitpai.co.uk</a> <p>Regards, <br> Rohit Pai <br> <a href="mailto:rohit@rohitpai.co.uk">rohit@rohitpai.co.uk</a>
</body> </body>
</html> </html>
"; HEREA;
mail($data["email"], $data["subject"], $message1, $headers1); mail($data["email"], $data["subject"], $message1, $headers1);
// email to me // email to me
$headers2 = "From: noreply@rohitpai.co.uk\r\n"; $headers2 = "From: noreply@rohitpai.co.uk\r\n";
$headers2 .= "Reply-To: {$data['email']}\r\n"; $headers2 .= "Reply-To: {$data['email']}\r\n";
$headers2 .= "MIME-Version: 1.0\r\n"; $headers2 .= "MIME-Version: 1.0\r\n";
$headers2 .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers2 .= "Content-Type: text/html; charset=UTF-8\r\n";
$message2 = " $message2 = <<<HEREB
<html lang=\"en\"> <html lang="en">
<head> <head>
<title>{$data['subject']}</title> <title>{$data['subject']}</title>
<style> <style>
@import url(\"https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Share+Tech+Mono&family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap\"); @import url("https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Share+Tech+Mono&family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap");
body { body {
font-family: Noto Sans KR, sans-serif; font-family: Noto Sans KR, sans-serif;
font-style: normal; font-style: normal;
@@ -237,146 +196,17 @@ $app->post("/contact", function (Request $request, Response $response)
<tr> <tr>
<td>{$data['fName']}</td> <td>{$data['fName']}</td>
<td>{$data['lName']}</td> <td>{$data['lName']}</td>
<td><a href=\"mailto:{$data['email']}\">{$data['email']}</a></td> <td><a href="mailto:{$data['email']}">{$data['email']}</a></td>
<td>{$data['subject']}</td> <td>{$data['subject']}</td>
<td>{$data['message']}</td> <td>{$data['message']}</td>
</tr> </tr>
</table> </table>
</body> </body>
</html> </html>
"; HEREB;
mail("rohit@rohitpai.co.uk", "{$data['fName']} {$data['lName']} filled in the form", $message2, $headers2); mail("rohit@rohitpai.co.uk", "{$data['fName']} {$data['lName']} filled in the form", $message2, $headers2);
return $response->withStatus(201); return $response->withStatus(201);
}); });
$app->post("/user/login", function (Request $request, Response $response)
{
global $user;
// get request data
$data = $request->getParsedBody();
if (empty($data["username"]) || empty($data["password"]))
{
// uh oh user sent empty data
return $response->withStatus(400);
}
if ($user->checkUser($data["username"], $data["password"]))
{
// yay, user is logged in
$_SESSION["token"] = $user->createToken($data["username"]);
$_SESSION["username"] = $data["username"];
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
return $response;
}
return $response->withStatus(401);
});
$app->get("/user/isLoggedIn", function (Request $request, Response $response)
{
global $user;
if (empty($_SESSION["token"]) && empty($_SESSION["username"]))
{
// uh oh user not logged in
return $response->withStatus(401);
}
if (empty($_SESSION["token"]))
{
// user is logged in but no token was created
$_SESSION["token"] = $user->createToken($_SESSION["username"]);
return $response;
}
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
return $response;
});
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
{
global $user;
if (empty($args["email"]))
{
// uh oh sent empty data
return $response->withStatus(400);
}
if ($user->checkEmail($args["email"]))
{
// yay email does exist
$_SESSION["resetToken"] = $user->sendResetEmail($args["email"]);
$_SESSION["resetEmail"] = $args["email"];
return $response;
}
return $response->withStatus(404);
});
$app->get("/user/resendEmail", function (Request $request, Response $response)
{
if (empty($_SESSION["resetToken"]))
{
// uh oh not authorized to resend email
return $response->withStatus(401);
}
global $user;
$_SESSION["resetToken"] = $user->sendResetEmail($_SESSION["resetEmail"]);
return $response;
});
$app->get("/user/checkResetCode/{code}", function (Request $request, Response $response, array $args)
{
if (empty($args["code"]))
{
// uh oh sent empty data
return $response->withStatus(400);
}
if ($_SESSION["resetToken"] === $args["code"])
{
// yay, code code matches
return $response;
}
return $response->withStatus(401);
});
$app->post("/user/changePassword", function (Request $request, Response $response)
{
global $user;
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
{
// uh oh not authorized to change password
return $response->withStatus(401);
}
$data = $request->getParsedBody();
if (empty($data["password"]))
{
// uh oh sent empty data
return $response->withStatus(400);
}
if ($user->changePassword($_SESSION["resetEmail"], $data["password"]))
{
// yay, password changed
unset($_SESSION["resetToken"]);
unset($_SESSION["resetEmail"]);
return $response;
}
return $response->withStatus(500);
});
$app->post("/projectData", function (Request $request, Response $response)
{
$response->getBody()->write(json_encode(array("test" => "test")));
return $response;
});
$app->run(); $app->run();
-91
View File
@@ -1,91 +0,0 @@
<?php
// middleware
namespace api;
use Slim\App;
use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
/**
* Middleware
* Define all middleware functions
*/
class middleware
{
/**
* Constructor for middleware
* @param App $app - Slim App
*/
function __construct(App $app)
{
$this->baseMiddleware($app);
$this->sameSiteConfig($app);
$this->jwtAuth($app);
$this->returnAsJSON($app);
}
/**
* Base middleware
* @param App $app - Slim App
*/
function baseMiddleware(App $app): void
{
$app->addRoutingMiddleware();
}
/**
* SameSite Cookie Configuration
* @param App $app - Slim App
*/
function sameSiteConfig(App $app): void
{
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
$app->add(new SameSiteCookieMiddleware($ssConfig));
}
/**
* Return all responses as JSON
* @param App $app - Slim App
*/
function returnAsJSON(App $app): void
{
$app->add(function ($request, $handler)
{
$response = $handler->handle($request);
return $response->withHeader("Content-Type", "application/json");
});
}
/**
* JWT Authentication
* @param App $app - Slim App
*/
function jwtAuth(App $app): void
{
$jwtSecret = getSecretKey();
$app->add(new JwtAuthentication([
"rules" => [
new RequestPathRule([
"path" => ["/api/projectData", "/api/timeline/[a-z]*", "/api/user/testMethod"],
"ignore" => ["/api/contact", "/api/user/login", "/api/user/changePassword"]
]),
new RequestMethodRule([
"ignore" => ["OPTIONS", "GET"]
])
],
"secret" => $jwtSecret,
"error" => function ($response)
{
session_destroy();
$response->getBody()->write(json_encode(array("status" => "401", "message" =>
"Unauthorized, please provide a valid token")));
return $response->withStatus(401);
}
]));
$app->addErrorMiddleware(true, true, true);
}
}
+230
View File
@@ -0,0 +1,230 @@
<?php
namespace api\project;
use api\utils\imgUtils;
use PDO;
use Psr\Http\Message\UploadedFileInterface;
use function api\utils\dbConn;
require_once __DIR__ . "/../utils/config.php";
require_once __DIR__ . "/../utils/imgUtils.php";
/**
* Project Data Class
* Define all functions which either get, update, create or delete timeline data
*/
class projectData
{
/**
* Get all project data
* @return array<array> - Array of all project data or error message
*/
public function getProjectData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, title, isMainProject, information, imgLocation, projectLink, gitLink FROM projects ORDER BY isMainProject DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, project data not found");
}
/**
* Update project data in the database with the given ID
* @param string $ID - ID of the project in the database to update
* @param string $title - Title of the project
* @param bool $isMainProject - Is the project a main project or not
* @param string $information - Information about the project
* @param string $projectLink - Link to the project
* @param string $gitLink - Link to the git repository
* @return bool|string - True if project was updated, false if not and there was an error, or an error string
*/
public function updateProjectData(string $ID, string $title, bool $isMainProject, string $information, string $projectLink, string $gitLink): bool|string
{
$conn = dbConn();
$stmtMainProject = $conn->prepare("SELECT isMainProject FROM projects WHERE ID = :ID");
$stmtMainProject->bindParam(":ID", $ID);
$stmtMainProject->execute();
$result = $stmtMainProject->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "project not found";
}
if (!$isMainProject && $result["isMainProject"] === "1")
{
return "unset main project";
}
if ($isMainProject)
{
$stmtMainProject = $conn->prepare("UPDATE projects SET isMainProject = 0 WHERE isMainProject = 1;");
$stmtMainProject->execute();
}
$stmt = $conn->prepare("UPDATE projects SET title = :title, isMainProject = :isMainProject, information = :information, projectLink = :projectLink, gitLink = :gitLink WHERE ID = :ID");
$stmt->bindParam(":title", $title);
$isMainProj = $isMainProject ? 1 : 0;
$stmt->bindParam(":isMainProject", $isMainProj);
$stmt->bindParam(":information", $information);
$stmt->bindParam(":projectLink", $projectLink);
$stmt->bindParam(":gitLink", $gitLink);
$stmt->bindParam(":ID", $ID);
return $stmt->execute();
}
/**
* Delete project data from the database
* @param int $ID - ID of the project in the database to delete
* @return string - True if project was deleted, false if not and there was an error
*/
public function deleteProjectData(int $ID): string
{
$conn = dbConn();
// check if the project is a main project if it is return false
$stmtMainProject = $conn->prepare("SELECT isMainProject FROM projects WHERE ID = :ID");
$stmtMainProject->bindParam(":ID", $ID);
$stmtMainProject->execute();
$result = $stmtMainProject->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "project not found";
}
if ($result["isMainProject"] === "1")
{
return "cannot delete";
}
$this->deleteImage($ID);
$stmt = $conn->prepare("DELETE FROM projects WHERE ID = :ID");
$stmt->bindParam(":ID", $ID);
$stmt->execute();
if ($stmt->rowCount() > 0)
{
return "ok";
}
return "error";
}
/**
* Add project data to the database
* @param string $title - Title of the project
* @param string $isMainProject - Is the project a main project or not
* @param string $information - Information about the project
* @param string $projectLink - Link to the project
* @param string $gitLink - Link to the github repository
* @return int|bool - ID of the project if it was added, false if not and there was an error
*/
public function addProjectData(string $title, string $isMainProject, string $information, string $projectLink, string $gitLink): int|bool
{
$conn = dbConn();
if ($isMainProject === "true")
{
$stmtMainProject = $conn->prepare("UPDATE projects SET isMainProject = 0 WHERE isMainProject = 1;");
$stmtMainProject->execute();
}
$stmt = $conn->prepare("INSERT INTO projects (title, isMainProject, information, projectLink, gitLink) VALUES (:title, :isMainProject, :information, :projectLink, :gitLink)");
$stmt->bindParam(":title", $title);
$isMainProj = ($isMainProject === "true") ? 1 : 0;
$stmt->bindParam(":isMainProject", $isMainProj);
$stmt->bindParam(":information", $information);
$stmt->bindParam(":projectLink", $projectLink);
$stmt->bindParam(":gitLink", $gitLink);
$stmt->execute();
if ($stmt->rowCount() > 0)
{
return $conn->lastInsertId();
}
return false;
}
/**
* Upload the image to the server and update the database with the new image location
* @param int $ID - ID of the project in the database to update
* @param UploadedFileInterface $img - Image preview of the project
* @return string|array - String with error message or array with the new image location
*/
public function uploadImage(int $ID, UploadedFileInterface $img): string|array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID FROM projects WHERE ID = :ID");
$stmt->bindParam(":ID", $ID);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "Project with ID $ID not found";
}
$targetDir = "../imgs/projects/";
$imgUtils = new imgUtils();
$targetFile = $imgUtils->uploadFile($targetDir, $img);
if (!is_array($targetFile))
{
return $targetFile;
}
if (file_exists($targetFile["imgLocation"]))
{
$this->deleteImage($ID);
// update the database with the new image location
$stmt = $conn->prepare("UPDATE projects SET imgLocation = :imgLocation WHERE ID = :ID");
$stmt->bindParam(":imgLocation", $targetFile["imgLocation"]);
$stmt->bindParam(":ID", $ID);
$stmt->execute();
if ($stmt->rowCount() > 0)
{
return array("imgLocation" => $targetFile["imgLocation"]);
}
return "Couldn't update the database";
}
return "Couldn't upload the image";
}
/**
* Delete the image from the server
* @param int $ID - ID of the project in the database
*/
private function deleteImage(int $ID): void
{
$conn = dbConn();
$imgStmt = $conn->prepare("SELECT imgLocation FROM projects WHERE ID = :ID");
$imgStmt->bindParam(":ID", $ID);
$imgStmt->execute();
$imgLocation = $imgStmt->fetch(PDO::FETCH_ASSOC)["imgLocation"];
if ($imgLocation != null)
{
unlink($imgLocation);
}
}
}
+171
View File
@@ -0,0 +1,171 @@
<?php
namespace api\project;
require_once __DIR__ . "/../utils/routesInterface.php";
require_once "projectData.php";
use api\utils\routesInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
class projectRoutes implements routesInterface
{
private projectData $projectData;
/**
* constructor used to instantiate a base project routes, to be used in the index.php file.
* @param App $app - the slim app used to create the routes
*/
public function __construct(App $app)
{
$this->projectData = new projectData();
$this->createRoutes($app);
}
/**
* creates the routes for the project
* @param App $app - the slim app used to create the routes
* @return void - returns nothing
*/
public function createRoutes(App $app): void
{
$app->get("/projectData", function (Request $request, Response $response)
{
$result = $this->projectData->getProjectData();
$json = json_encode($result);
$response->getBody()->write($json);
if (array_key_exists("errorMessage", $result))
{
$response->withStatus(404);
}
//use content type json to indicate json data on frontend.
return $response;
});
$app->patch("/projectData/{id}", function (Request $request, Response $response, array $args)
{
$data = $request->getParsedBody();
if ($args["id"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an ID")));
return $response->withStatus(400);
}
if (empty($data["title"]) || empty($data["isMainProject"]) || empty($data["information"]) || empty($data["gitLink"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
$isMainProject = $data["isMainProject"] === "true";
$update = $this->projectData->updateProjectData($args["id"], $data["title"], $isMainProject, $data["information"], $data["projectLink"], $data["gitLink"]);
if ($update === "project not found")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Project with ID " . $args["id"] . " not found")));
return $response->withStatus(404);
}
if ($update === "unset main project")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Can't unset project as main project, try updating another project as the main project")));
return $response->withStatus(400);
}
if (!$update)
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
return $response;
});
$app->delete("/projectData/{id}", function (Request $request, Response $response, array $args)
{
if ($args["id"] == null)
{
$response->getBody()->write(json_encode(array("error" => "Please provide an ID")));
return $response->withStatus(400);
}
$message = $this->projectData->deleteProjectData($args["id"]);
if ($message === "project not found")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Project with ID " . $args["id"] . " not found")));
return $response->withStatus(404);
}
if ($message === "cannot delete")
{
//uh oh cannot delete the main project
$response->getBody()->write(json_encode(array("error" => "Cannot delete the main project")));
return $response->withStatus(409);
}
if ($message === "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
return $response;
});
$app->post("/projectData", function (Request $request, Response $response)
{
$data = $request->getParsedBody();
if (empty($data["title"]) || empty($data["isMainProject"]) || empty($data["information"]) || empty($data["gitLink"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400)->withStatus(201);
}
$insertedID = $this->projectData->addProjectData($data["title"], $data["isMainProject"], $data["information"], $data["projectLink"], $data["gitLink"]);
if (!is_int($insertedID))
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong", "message" => $insertedID)));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("ID" => $insertedID)));
return $response->withStatus(201);
});
$app->post("/projectImage/{id}", function (Request $request, Response $response, array $args)
{
$files = $request->getUploadedFiles();
if (empty($args["id"]) || empty($files))
{
// uh oh only some of the data was sent
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
$message = $this->projectData->uploadImage($args["id"], $files["img"]);
if (!is_array($message))
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => $message)));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode($message));
return $response->withStatus(201);
});
}
}
-32
View File
@@ -1,32 +0,0 @@
<?php
namespace api;
use PDO;
require_once "./config.php";
/**
* Project Data Class
* Define all functions which either get, update, create or delete timeline data
*/
class projectData
{
/**
* Get all project data
* @return array - Array of all project data or error message
*/
function getProjectData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT title, isMainProject, information, imgLocation, projectLink, githubLink FROM projects order by date LIMIT 4;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, project data not found");
}
}
+233
View File
@@ -0,0 +1,233 @@
<?php
namespace api\timeline;
use PDO;
use function api\utils\dbConn;
require_once __DIR__ . "/../utils/config.php";
/**
* TimelineData class
* Define all functions which either get, update, create or delete timeline data
*/
class timelineData
{
/**
* Get all education data
* @return array<array> - Array of all education data or error message
*/
public function getEduData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, startPeriod, endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, edu data not found");
}
/**
* Get all work data
* @return array - Array of all work data or error message
*/
public function getWorkData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT ID, startPeriod, endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, work data not found");
}
/**
* Update education data
* @param string $dateFrom - Start date
* @param string $dateTo - End date
* @param string $grade - Grade
* @param string $course - Course
* @param string $ID - ID of the education data
* @return string - "not found" if the ID is not found, "ok" if successful, "error" if not
*/
public function updateEduData(string $dateFrom, string $dateTo, string $grade, string $course, string $ID): string
{
$conn = dbConn();
$chkStmt = $conn->prepare("SELECT ID FROM edu WHERE ID = :id;");
$chkStmt->bindParam(":id", $ID);
$chkStmt->execute();
$result = $chkStmt->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "not found";
}
$stmt = $conn->prepare("UPDATE edu SET startPeriod = :dateFrom, endPeriod = :dateTo, grade = :grade, course = :course WHERE ID = :id;");
$stmt->bindParam(":dateFrom", $dateFrom);
$stmt->bindParam(":dateTo", $dateTo);
$stmt->bindParam(":grade", $grade);
$stmt->bindParam(":course", $course);
$stmt->bindParam(":id", $ID);
if ($stmt->execute())
{
return "ok";
}
return "error";
}
/**
* Update work data
* @param string $dateFrom - Start date
* @param string $dateTo - End date
* @param string $companyName - Company name
* @param string $area - Area
* @param string $title - Title
* @param string $ID - ID of the work data
* @return string - "not found" if the ID is not found, "ok" if successful, "error" if not
*/
public function updateWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title, string $ID): string
{
$conn = dbConn();
$chkStmt = $conn->prepare("SELECT ID FROM work WHERE ID = :id;");
$chkStmt->bindParam(":id", $ID);
$chkStmt->execute();
$result = $chkStmt->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "not found";
}
$conn = dbConn();
$stmt = $conn->prepare("UPDATE work SET startPeriod = :dateFrom, endPeriod = :dateTo, companyName = :companyName, area = :area, title = :title WHERE ID = :id;");
$stmt->bindParam(":dateFrom", $dateFrom);
$stmt->bindParam(":dateTo", $dateTo);
$stmt->bindParam(":companyName", $companyName);
$stmt->bindParam(":area", $area);
$stmt->bindParam(":title", $title);
$stmt->bindParam(":id", $ID);
if ($stmt->execute())
{
return "ok";
}
return "error";
}
/**
* Delete education data by ID
* @param int $ID
* @return string - "not found" if the ID is not found, "ok" if successful, "error" if not
*/
public function deleteEduData(int $ID): string
{
$conn = dbConn();
$chkStmt = $conn->prepare("SELECT ID FROM edu WHERE ID = :id;");
$chkStmt->bindParam(":id", $ID);
$chkStmt->execute();
$result = $chkStmt->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "not found";
}
$stmt = $conn->prepare("DELETE FROM edu WHERE ID = :id;");
$stmt->bindParam(":id", $ID);
if ($stmt->execute())
{
return "ok";
}
return "error";
}
/**
* Delete work data by ID
* @param int $ID
* @return string - "not found" if the ID is not found, "ok" if successful, "error" if not
*/
function deleteWorkData(int $ID): string
{
$conn = dbConn();
$chkStmt = $conn->prepare("SELECT ID FROM work WHERE ID = :id;");
$chkStmt->bindParam(":id", $ID);
$chkStmt->execute();
$result = $chkStmt->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "not found";
}
$stmt = $conn->prepare("DELETE FROM work WHERE ID = :id;");
$stmt->bindParam(":id", $ID);
if ($stmt->execute())
{
return "ok";
}
return "error";
}
/**
* Create new education data
* @param string $dateFrom - Start date
* @param string $dateTo - End date
* @param string $grade - Grade
* @param string $course - Course
* @return bool|int - ID of the new education data or false if not successful
*/
public function addEduData(string $dateFrom, string $dateTo, string $grade, string $course): bool|int
{
$conn = dbConn();
$stmt = $conn->prepare("INSERT INTO edu (startPeriod, endPeriod, grade, course) VALUES (:dateFrom, :dateTo, :grade, :course);");
$stmt->bindParam(":dateFrom", $dateFrom);
$stmt->bindParam(":dateTo", $dateTo);
$stmt->bindParam(":grade", $grade);
$stmt->bindParam(":course", $course);
if ($stmt->execute())
{
return $conn->lastInsertId();
}
return false;
}
/**
* Create new work data
* @param string $dateFrom - Start date
* @param string $dateTo - End date
* @param string $companyName - Company name
* @param string $area - Area
* @param string $title - Title
* @return bool|int - ID of the new work data if successful, false if not
*/
public function addWorkData(string $dateFrom, string $dateTo, string $companyName, string $area, string $title): bool|int
{
$conn = dbConn();
$stmt = $conn->prepare("INSERT INTO work (startPeriod, endPeriod, companyName, area, title) VALUES (:dateFrom, :dateTo, :companyName, :area, :title);");
$stmt->bindParam(":dateFrom", $dateFrom);
$stmt->bindParam(":dateTo", $dateTo);
$stmt->bindParam(":companyName", $companyName);
$stmt->bindParam(":area", $area);
$stmt->bindParam(":title", $title);
if ($stmt->execute())
{
return $conn->lastInsertId();
}
return false;
}
}
+222
View File
@@ -0,0 +1,222 @@
<?php
namespace api\timeline;
require_once __DIR__ . "/../utils/routesInterface.php";
require_once "timelineData.php";
use api\utils\routesInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
class timelineRoutes implements routesInterface
{
private timelineData $timelineData;
/**
* constructor used to instantiate a base timeline routes, to be used in the index.php file.
* @param App $app - the slim app used to create the routes
*/
public function __construct(App $app)
{
$this->timelineData = new timelineData();
$this->createRoutes($app);
}
/**
* creates the routes for the timeline
* @param App $app - the slim app used to create the routes
* @return void - returns nothing
*/
public function createRoutes(App $app): void
{
$app->get("/timelineData/{timeline}", function (Request $request, Response $response, array $args)
{
//check if route is available if it is get the data
//otherwise return an error
if ($args["timeline"] == "edu")
{
$response->getBody()->write(json_encode($this->timelineData->getEduData()));
return $response;
}
if ($args["timeline"] == "work")
{
$response->getBody()->write(json_encode($this->timelineData->getWorkData()));
return $response;
}
// something went wrong
$response->getBody()->write(json_encode(array("errorMessage" => "Error, timeline data not found")));
return $response->withStatus(404);
});
$app->patch("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
{
$data = $request->getParsedBody();
if ($args["timeline"] == "edu" && $args["id"] != null)
{
if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
$message = $this->timelineData->updateEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"], $args["id"]);
if ($message == "not found")
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Edu data with ID " . $args["id"] . " was not found")));
return $response->withStatus(404);
}
if ($message == "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
$response->withStatus(201);
return $response;
}
if ($args["timeline"] == "work" && $args["id"] != "undefined")
{
if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["companyName"]) || empty($data["area"]) || empty($data["title"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
$message = $this->timelineData->updateWorkData($data["dateFrom"], $data["dateTo"], $data["companyName"], $data["area"], $data["title"], $args["id"]);
if ($message == "not found")
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Work data with ID " . $args["id"] . " was not found")));
return $response->withStatus(404);
}
if ($message == "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
$response->withStatus(201);
return $response;
}
$response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
return $response->withStatus(400);
});
$app->delete("/timelineData/{timeline}/{id}", function (Request $request, Response $response, array $args)
{
if ($args["timeline"] == "edu" && $args["id"] != null)
{
$message = $this->timelineData->deleteEduData($args["id"]);
if ($message == "not found")
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Edu data with ID " . $args["id"] . " was not found")));
return $response->withStatus(404);
}
if ($message == "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
return $response;
}
if ($args["timeline"] == "work" && $args["id"] != null)
{
$message = $this->timelineData->deleteWorkData($args["id"]);
if ($message == "not found")
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Work data with ID " . $args["id"] . " was not found")));
return $response->withStatus(404);
}
if ($message == "error")
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
return $response;
}
$response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
return $response->withStatus(400);
});
$app->post("/timelineData/{timeline}", function (Request $request, Response $response, array $args)
{
$data = $request->getParsedBody();
if ($args["timeline"] == "edu")
{
if (empty($data["dateFrom"]) || empty($data["dateTo"]) || empty($data["grade"]) || empty($data["course"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
$insertedID = $this->timelineData->addEduData($data["dateFrom"], $data["dateTo"], $data["grade"], $data["course"]);
if (!is_int($insertedID))
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("ID" => $insertedID)));
$response->withStatus(201);
return $response;
}
if ($args["timeline"] == "work")
{
if (empty($data["dateFrom"]) || empty($data["companyName"]) || empty($data["area"]) || empty($data["title"]))
{
// uh oh sent some empty data
$response->getBody()->write(json_encode(array("error" => "Only some of the data was sent")));
return $response->withStatus(400);
}
if (empty($data["dateTo"]))
{
$data["dateTo"] = "";
}
$insertedID = $this->timelineData->addWorkData($data["dateFrom"], $data["dateTo"], $data["companyName"], $data["area"], $data["title"]);
if (!is_int($insertedID))
{
// uh oh something went wrong
$response->getBody()->write(json_encode(array("error" => "Something went wrong")));
return $response->withStatus(500);
}
$response->getBody()->write(json_encode(array("ID" => $insertedID)));
$response->withStatus(201);
return $response;
}
$response->getBody()->write(json_encode(array("error" => "The correct data was not sent")));
return $response->withStatus(400);
});
}
}
-53
View File
@@ -1,53 +0,0 @@
<?php
namespace api;
use PDO;
require_once "./config.php";
/**
* TimelineData class
* Define all functions which either get, update, create or delete timeline data
*/
class timelineData
{
/**
* Get all education data
* @return array - Array of all education data or error message
*/
function getEduData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT DATE_FORMAT(startPeriod, '%b, %Y') as startPeriod, DATE_FORMAT(endPeriod, '%b, %Y') as endPeriod, grade, course FROM edu ORDER BY startPeriod DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, edu data not found");
}
/**
* Get all work data
* @return array - Array of all work data or error message
*/
function getWorkData(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT DATE_FORMAT(startPeriod, '%b, %Y') as startPeriod, DATE_FORMAT(endPeriod, '%b, %Y') as endPeriod, companyName, area, title FROM work ORDER BY work.startPeriod DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, work data not found");
}
}
+62 -24
View File
@@ -1,32 +1,37 @@
<?php <?php
namespace api;
namespace api\user;
use Firebase\JWT\JWT; use Firebase\JWT\JWT;
use PDO; use PDO;
use function api\utils\dbConn;
use function api\utils\getSAMLSettings;
use function api\utils\getSecretKey;
require_once "./config.php"; require_once __DIR__ . "/../utils/config.php";
/** /**
* User Class * User Class
* Define all functions which either check, update or delete user data * Define all functions which either check, update or delete userData data
*/ */
class user class userData
{ {
/** /**
* Check if user exists and can be logged in * Check if userData exists and can be logged in
* @param $username string - Username * @param $username string - Username
* @param $password string - Password * @param $password string - Password
* @return bool - True if logged in, false if not * @return bool - True if logged in, false if not
*/ */
function checkUser(string $username, string $password): bool public function checkUser(string $username, string $password): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username"); $stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
$stmt->bindParam(":username", $username); $stmt->bindParam(":username", $username);
$stmt->execute(); $stmt->execute();
// set the resulting array to associative // set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC); $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result) if ($result)
{ {
if (password_verify($password, $result[0]["password"])) if (password_verify($password, $result[0]["password"]))
@@ -43,18 +48,18 @@ class user
* @param $username string - Username * @param $username string - Username
* @return string - JWT token * @return string - JWT token
*/ */
function createToken(string $username): string public function createToken(string $username): string
{ {
$now = time(); $now = time();
$future = strtotime('+6 hour',$now); $future = strtotime('+2 day', $now);
$secretKey = getSecretKey(); $secretKey = getSecretKey();
$payload = [ $payload = [
"jti"=>$username, "jti" => $username,
"iat"=>$now, "iat" => $now,
"exp"=>$future "exp" => $future
]; ];
return JWT::encode($payload,$secretKey,"HS256"); return JWT::encode($payload, $secretKey, "HS256");
} }
/** /**
@@ -62,7 +67,7 @@ class user
* @param string $email - Email to check * @param string $email - Email to check
* @return bool - True if email exists, false if not * @return bool - True if email exists, false if not
*/ */
function checkEmail(string $email): bool public function checkEmail(string $email): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE email = :email"); $stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
@@ -80,24 +85,24 @@ class user
} }
/** /**
* Send a verification email to the user * Send a verification email to the userData
* @param $email - email address of the user * @param $email - email address of the userData
* @return string - verification code * @return string - verification code
*/ */
function sendResetEmail($email): string public function sendResetEmail($email): string
{ {
//generate a random token and email the address //generate a random token and email the address
$token = uniqid("rpe-"); $token = uniqid("rpe-");
$headers1 = "From: noreply@rohitpai.co.uk\r\n"; $headers1 = "From: noreply@rohitpai.co.uk\r\n";
$headers1 .= "MIME-Version: 1.0\r\n"; $headers1 .= "MIME-Version: 1.0\r\n";
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
$message = " $message = "
<!doctype html> <!doctype html>
<html lang='en'> <html lang='en'>
<head> <head>
<meta charset='UTF-8'> <meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'> <meta name='viewport' content='width=device-width, userData-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'>
<meta http-equiv='X-UA-Compatible' content='ie=edge'> <meta http-equiv='X-UA-Compatible' content='ie=edge'>
<title>Document</title> <title>Document</title>
</head> </head>
@@ -108,7 +113,7 @@ class user
</body> </body>
</html> </html>
"; ";
mail($email, "Reset Password Verification Code", $message, $headers1); mail($email, "Reset Password Verification Code", $message, $headers1);
return $token; return $token;
} }
@@ -116,17 +121,17 @@ class user
/** /**
* Change password for an email with new password * Change password for an email with new password
* @param $email string Email * @param $email string Email
* @param $password string Password * @param $password string Password
* @return bool - true if the password was changed, false if not * @return bool - true if the password was changed, false if not
*/ */
function changePassword(string $email, string $password): bool public function changePassword(string $email, string $password): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email"); $stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email");
$newPwd = password_hash($password, PASSWORD_BCRYPT); $newPwd = password_hash($password, PASSWORD_BCRYPT);
$stmt->bindParam(":password", $newPwd); $stmt->bindParam(":password", $newPwd);
$stmt->bindParam(":email", $email); $stmt->bindParam(":email", $email);
if ($stmt->execute()) if ($stmt->execute())
{ {
return true; return true;
@@ -134,5 +139,38 @@ class user
return false; return false;
} }
/**
* Get the SAML settings
* @return array - SAML settings
*/
public function getSamlConf(): array
{
return getSAMLSettings();
}
/**
* Check if the SAML user exists
* @param string $username - Username
* @param string $email - Email
* @return bool - True if the user exists, false if not
*/
public function checkSAMLUser(string $username, string $email): bool
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username AND email = :email");
$stmt->bindParam(":username", $username);
$stmt->bindParam(":email", $email);
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return true;
}
return false;
}
} }
+217
View File
@@ -0,0 +1,217 @@
<?php
namespace api\user;
require_once __DIR__ . "/../utils/routesInterface.php";
require_once "userData.php";
use api\utils\routesInterface;
use OneLogin\Saml2\Auth;
use OneLogin\Saml2\Error;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
class userRoutes implements routesInterface
{
private userData $user;
private Auth $samlAuth;
/**
* constructor used to instantiate base user routes, to be used in the index.php file.
* @param App $app - the slim app used to create the routes
* @throws Error
*/
public function __construct(App $app)
{
$this->user = new userData();
$this->samlAuth = new Auth($this->user->getSamlConf());
$this->createRoutes($app);
}
/**
* creates the routes for the user
* @param App $app - the slim app used to create the routes
* @return void - returns nothing
*/
public function createRoutes(App $app): void
{
$app->get("/user/login", function (Request $request, Response $response)
{
$this->samlAuth->login();
});
$app->get("/user/logout", function (Request $request, Response $response)
{
session_unset();
return $response;
});
$app->get("/user/isLoggedIn", function (Request $request, Response $response)
{
if (empty($_SESSION["token"]) && empty($_SESSION["username"]))
{
// uh oh user not logged in
return $response->withStatus(401);
}
$inactive = 60 * 60 * 48; // 2 days
$sessionLife = time() - $_SESSION["timeout"];
if ($sessionLife > $inactive)
{
// uh oh user session expired
session_destroy();
return $response->withStatus(401);
}
if (empty($_SESSION["token"]))
{
// user is logged in but no token was created
$_SESSION["token"] = $this->user->createToken($_SESSION["username"]);
return $response->withStatus(201);
}
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
return $response;
});
$app->get("/user/metadata", function (Request $request, Response $response)
{
$settings = $this->samlAuth->getSettings();
$metadata = $settings->getSPMetadata();
$errors = $settings->validateMetadata($metadata);
if (empty($errors))
{
$response->getBody()->write($metadata);
return $response->withHeader("Content-Type", "text/xml");
}
$response->getBody()->write(json_encode(array("error" => $errors)));
return $response->withStatus(500);
});
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
{
if (empty($args["email"]))
{
// uh oh sent empty data
return $response->withStatus(400);
}
if ($this->user->checkEmail($args["email"]))
{
// yay email does exist
$_SESSION["resetToken"] = $this->user->sendResetEmail($args["email"]);
$_SESSION["resetEmail"] = $args["email"];
return $response;
}
return $response->withStatus(404);
});
$app->get("/user/resendEmail", function (Request $request, Response $response)
{
if (empty($_SESSION["resetToken"]))
{
// uh oh not authorized to resend email
return $response->withStatus(401);
}
$_SESSION["resetToken"] = $this->user->sendResetEmail($_SESSION["resetEmail"]);
return $response;
});
$app->get("/user/checkResetCode/{code}", function (Request $request, Response $response, array $args)
{
if (empty($args["code"]))
{
// uh oh sent empty data
return $response->withStatus(400);
}
if ($_SESSION["resetToken"] === $args["code"])
{
// yay, code code matches
return $response;
}
return $response->withStatus(401);
});
$app->post("/user/login", function (Request $request, Response $response)
{
// get request data
$data = $request->getParsedBody();
if (empty($data["username"]) || empty($data["password"]))
{
// uh oh user sent empty data
return $response->withStatus(400);
}
if ($this->user->checkUser($data["username"], $data["password"]))
{
// yay, user is logged in
$_SESSION["token"] = $this->user->createToken($data["username"]);
$_SESSION["username"] = $data["username"];
$inactive = 60 * 60 * 48; // 2 days
$_SESSION["timeout"] = time() + $inactive;
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
return $response;
}
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
return $response->withStatus(401);
});
$app->post("/user/acs", function (Request $request, Response $response)
{
$this->samlAuth->processResponse();
$attributes = $this->samlAuth->getAttributes();
$username = $attributes["username"][0];
$email = $attributes["email"][0];
if ($this->user->checkSAMLUser($username, $email))
{
// yay, user is logged in
$_SESSION["token"] = $this->user->createToken($username);
$_SESSION["username"] = $username;
$_SESSION["email"] = $email;
$inactive = 60 * 60 * 48; // 2 days
$_SESSION["timeout"] = time() + $inactive;
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/")->withStatus(302);
}
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
return $response->withStatus(401);
});
$app->post("/user/changePassword", function (Request $request, Response $response)
{
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
{
// uh oh not authorized to change password
return $response->withStatus(401);
}
$data = $request->getParsedBody();
if (empty($data["password"]))
{
// uh oh sent empty data
return $response->withStatus(400);
}
if ($this->user->changePassword($_SESSION["resetEmail"], $data["password"]))
{
// yay, password changed
unset($_SESSION["resetToken"]);
unset($_SESSION["resetEmail"]);
return $response->withStatus(201);
}
return $response->withStatus(500);
});
}
}
+152
View File
@@ -0,0 +1,152 @@
<?php
namespace api\utils\feedGenerator;
/**
* Universal Feed Writer
*
* FeedItem class - Used as a feed element in FeedWriter class
*
* @package UniversalFeedWriter
* @author Anis uddin Ahmad <anisniit@gmail.com>
* @link http://www.ajaxray.com/projects/rss
*/
class FeedItem
{
private array $elements = []; // Collection of feed elements
private string $version;
/**
* Constructor
*
* @param string $version (RSS1/RSS2/ATOM) RSS2 is the default.
*/
public function __construct(string $version = RSS2)
{
$this->version = $version;
}
/**
* Add an element to elements array
*
* @param string $elementName The tag name of an element
* @param string $content The content of the tag
* @param array|null $attributes Attributes (if any) in 'attrName' => 'attrValue' format
*/
public function addElement(string $elementName, string $content, ?array $attributes = null): void
{
$this->elements[$elementName]['name'] = $elementName;
$this->elements[$elementName]['content'] = $content;
$this->elements[$elementName]['attributes'] = $attributes;
}
/**
* Set multiple feed elements from an array.
* Elements that have attributes cannot be added by this method
*
* @param array $elementArray Array of elements in 'tagName' => 'tagContent' format.
*/
public function addElementArray(array $elementArray): void
{
foreach ($elementArray as $elementName => $content)
{
$this->addElement($elementName, $content);
}
}
/**
* Return the collection of elements in this feed item
*
* @return array
*/
public function getElements(): array
{
return $this->elements;
}
// Wrapper functions ------------------------------------------------------
/**
* Set the 'description' element of the feed item
*
* @param string $description The content of the 'description' element
*/
public function setDescription(string $description): void
{
$tag = ($this->version === ATOM) ? 'summary' : 'description';
$this->addElement($tag, $description);
}
/**
* Set the 'title' element of the feed item
*
* @param string $title The content of the 'title' element
*/
public function setTitle(string $title): void
{
$this->addElement('title', $title);
}
/**
* Set the 'date' element of the feed item
*
* @param string|int $date The content of the 'date' element
*/
public function setDate(string|int $date): void
{
if (!is_numeric($date))
{
$date = strtotime($date);
}
if ($this->version === ATOM)
{
$tag = 'updated';
$value = date(DATE_ATOM, $date);
}
elseif ($this->version === RSS2)
{
$tag = 'pubDate';
$value = date(DATE_RSS, $date);
}
else
{
$tag = 'dc:date';
$value = date("Y-m-d", $date);
}
$this->addElement($tag, $value);
}
/**
* Set the 'link' element of the feed item
*
* @param string $link The content of the 'link' element
*/
public function setLink(string $link): void
{
if ($this->version === RSS2 || $this->version === RSS1)
{
$this->addElement('link', $link);
}
else
{
$this->addElement('link', '', ['href' => $link]);
$this->addElement('id', FeedWriter::uuid($link, 'urn:uuid:'));
}
}
/**
* Set the 'encloser' element of the feed item
* For RSS 2.0 only
*
* @param string $url The url attribute of the encloser tag
* @param string $length The length attribute of the encloser tag
* @param string $type The type attribute of the encloser tag
*/
public function setEncloser(string $url, string $length, string $type): void
{
$attributes = ['url' => $url, 'length' => $length, 'type' => $type];
$this->addElement('enclosure', '', $attributes);
}
}
+386
View File
@@ -0,0 +1,386 @@
<?php
namespace api\utils\feedGenerator;
require_once "FeedItem.php";
/**
* Universal Feed Writer class
*
* Generate RSS 1.0, RSS 2.0, and Atom Feed
*
* @package UniversalFeedWriter
* @link http://www.ajaxray.com/projects/rss
*/
class FeedWriter
{
private array $channels = []; // Collection of channel elements
private array $items = []; // Collection of items as objects of FeedItem class
private array $data = []; // Store some other version-wise data
private array $CDATAEncoding = []; // The tag names that need to be encoded as CDATA
private string $version;
/**
* Constructor
*
* @param string $version The version (RSS1, RSS2, ATOM).
*/
public function __construct(string $version = RSS2)
{
$this->version = $version;
// Setting default values for essential channel elements
$this->channels['title'] = $version . ' Feed';
$this->channels['link'] = 'http://www.ajaxray.com/blog';
$this->channels["feedUrl"] = "http://example.com/feed";
// Tag names to encode in CDATA
$this->CDATAEncoding = ['description', 'content:encoded', 'summary'];
}
// Public functions
/**
* Set a channel element
*
* @param string $elementName Name of the channel tag
* @param string $content Content of the channel tag
*/
public function setChannelElement(string $elementName, string|array $content): void
{
$this->channels[$elementName] = $content;
}
/**
* Generate the actual RSS/Atom file
*/
public function generateFeed(): void
{
$this->printHead();
$this->printChannels();
$this->printItems();
$this->printTail();
}
/**
* Create a new FeedItem.
*
* @return FeedItem An instance of FeedItem class
*/
public function createNewItem(): FeedItem
{
$item = new FeedItem($this->version);
return $item;
}
/**
* Add a FeedItem to the main class
*
* @param FeedItem $feedItem An instance of FeedItem class
*/
public function addItem(FeedItem $feedItem): void
{
$this->items[] = $feedItem;
}
// Wrapper functions
/**
* Set the 'title' channel element
*
* @param string $title Value of 'title' channel tag
*/
public function setTitle(string $title): void
{
$this->setChannelElement('title', $title);
}
/**
* Set the 'description' channel element
*
* @param string $description Value of 'description' channel tag
*/
public function setDescription(string $description): void
{
$this->setChannelElement('description', $description);
}
/**
* Set the 'link' channel element
*
* @param string $link Value of 'link' channel tag
*/
public function setLink(string $link): void
{
$this->setChannelElement('link', $link);
}
/**
* Set the 'image' channel element
*
* @param string $title Title of the image
* @param string $link Link URL of the image
* @param string $url Path URL of the image
*/
public function setImage(string $title, string $link, string $url): void
{
$this->setChannelElement('image', ['title' => $title, 'link' => $link, 'url' => $url]);
}
/**
* Set the 'about' channel element. Only for RSS 1.0
*
* @param string $url Value of 'about' channel tag
*/
public function setChannelAbout(string $url): void
{
$this->data['ChannelAbout'] = $url;
}
// Other functions
/**
* Generates a UUID
*
* @param string $key An optional prefix
* @param string $prefix A prefix
* @return string The formatted UUID
*/
public static function uuid(?string $key = null, string $prefix = ''): string
{
$key = $key ?? uniqid((string)rand());
$chars = md5($key);
$uuid = substr($chars, 0, 8) . '-';
$uuid .= substr($chars, 8, 4) . '-';
$uuid .= substr($chars, 12, 4) . '-';
$uuid .= substr($chars, 16, 4) . '-';
$uuid .= substr($chars, 20, 12);
return $prefix . $uuid;
}
// Private functions
/**
* Prints the XML and RSS namespace
*/
private function printHead(): void
{
$out = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
if ($this->version == RSS2)
{
$out .= '<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
>' . PHP_EOL;
}
elseif ($this->version == RSS1)
{
$out .= '<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
>' . PHP_EOL;
}
elseif ($this->version == ATOM)
{
$out .= '<feed xmlns="http://www.w3.org/2005/Atom">' . PHP_EOL;
}
echo $out;
}
/**
* Closes the open tags at the end of the file
*/
private function printTail(): void
{
if ($this->version == RSS2)
{
echo '</channel>' . PHP_EOL . '</rss>';
}
elseif ($this->version == RSS1)
{
echo '</rdf:RDF>';
}
elseif ($this->version == ATOM)
{
echo '</feed>';
}
}
/**
* Creates a single node in XML format
*
* @param string $tagName Name of the tag
* @param mixed $tagContent Tag value as a string or an array of nested tags in 'tagName' => 'tagValue' format
* @param array|null $attributes Attributes (if any) in 'attrName' => 'attrValue' format
* @return string Formatted XML tag
*/
private function makeNode(string $tagName, $tagContent, ?array $attributes = null): string
{
$nodeText = '';
$attrText = '';
if (is_array($attributes))
{
foreach ($attributes as $key => $value)
{
$attrText .= " $key=\"$value\"";
}
}
if (is_array($tagContent) && $this->version == RSS1)
{
$attrText = ' rdf:parseType="Resource"';
}
$attrText .= (in_array($tagName, $this->CDATAEncoding) && $this->version == ATOM) ? ' type="html" ' : '';
$nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? "<{$tagName}{$attrText}><![CDATA[" : "<{$tagName}{$attrText}>";
if (is_array($tagContent))
{
foreach ($tagContent as $key => $value)
{
$nodeText .= $this->makeNode($key, $value);
}
}
else
{
$nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? $tagContent : htmlentities($tagContent);
}
$nodeText .= (in_array($tagName, $this->CDATAEncoding)) ? "]]></$tagName>" : "</$tagName>";
return $nodeText . PHP_EOL;
}
/**
* Prints channel elements
*/
private function printChannels(): void
{
// Start channel tag
switch ($this->version)
{
case RSS2:
echo '<channel>' . PHP_EOL;
break;
case RSS1:
echo (isset($this->data['ChannelAbout'])) ? "<channel rdf:about=\"{$this->data['ChannelAbout']}\">" : "<channel rdf:about=\"{$this->channels['link']}\">";
break;
}
// Print items of channel
foreach ($this->channels as $key => $value)
{
if ($this->version == ATOM && $key == 'link')
{
// ATOM prints the link element as an href attribute
echo $this->makeNode($key, '', ['href' => $value]);
// Add the id for ATOM
echo $this->makeNode('id', $this->uuid($value, 'urn:uuid:'));
}
else if ($this->version == ATOM && $key == 'feedUrl')
{
echo $this->makeNode('link', '', ['rel' => 'self', 'href' => $value]);
}
else
{
echo $this->makeNode($key, $value);
}
}
// RSS 1.0 has a special tag <rdf:Seq> with channel
if ($this->version == RSS1)
{
echo "<items>" . PHP_EOL . "<rdf:Seq>" . PHP_EOL;
foreach ($this->items as $item)
{
$thisItems = $item->getElements();
echo "<rdf:li resource=\"{$thisItems['link']['content']}\"/>" . PHP_EOL;
}
echo "</rdf:Seq>" . PHP_EOL . "</items>" . PHP_EOL . "</channel>" . PHP_EOL;
}
}
/**
* Prints formatted feed items
*/
private function printItems(): void
{
foreach ($this->items as $item)
{
$thisItems = $item->getElements();
// The argument is printed as rdf:about attribute of item in RSS 1.0
echo $this->startItem($thisItems['link']['content']);
foreach ($thisItems as $feedItem)
{
echo $this->makeNode($feedItem['name'], $feedItem['content'], $feedItem['attributes']);
}
echo $this->endItem();
}
}
/**
* Makes the starting tag of items
*
* @param string|false $about The value of about tag, which is used only for RSS 1.0
*/
private function startItem($about = false): void
{
if ($this->version == RSS2)
{
echo '<item>' . PHP_EOL;
}
elseif ($this->version == RSS1)
{
if ($about)
{
echo "<item rdf:about=\"$about\">" . PHP_EOL;
}
else
{
die("link element is not set.\n It's required for RSS 1.0 to be used as the about attribute of the item");
}
}
elseif ($this->version == ATOM)
{
echo "<entry>" . PHP_EOL;
}
}
/**
* Closes the feed item tag
*/
private function endItem(): void
{
if ($this->version == RSS2 || $this->version == RSS1)
{
echo '</item>' . PHP_EOL;
}
elseif ($this->version == ATOM)
{
echo "</entry>" . PHP_EOL;
}
}
/**
* Set the Feed URL
* @param string $string - The URL of the feed
* @return void
*/
public function setFeedURL(string $string): void
{
$this->setChannelElement("feedUrl", $string);
}
}
// Define constants for RSS 1.0, RSS 2.0, and Atom
const RSS1 = 'RSS 1.0';
const RSS2 = 'RSS 2.0';
const ATOM = 'ATOM';
+70
View File
@@ -0,0 +1,70 @@
<?php
namespace api\utils;
use Psr\Http\Message\UploadedFileInterface;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class imgUtils
{
/**
* Checks and uploads a file to the given directory
* @param string $targetDir - Directory to upload the file to
* @param UploadedFileInterface $img - File to upload
* @return string|array - String with error message or array with the location of the uploaded file
*/
public function uploadFile(string $targetDir, UploadedFileInterface $img): string|array
{
$targetFile = $targetDir . basename($img->getClientFilename());
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
// Check if file already exists
if (file_exists($targetFile))
{
return "The file already exists";
}
// Check file size
if ($img->getSize() > 2000000)
{
return "The file is too large, max 2MB";
}
// Allow certain file formats
if ($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" && $imageFileType != "gif")
{
return "Only JPG, JPEG, PNG & GIF files are allowed";
}
$img->moveTo($targetFile);
return array("imgLocation" => $targetFile);
}
/**
* Deletes a directory and all its contents
* @param string $path - Path to the directory to delete
*/
public function deleteDirectory(string $path): void
{
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path,
RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $file)
{
if ($file->isDir())
{
rmdir($file->getPathname());
}
else
{
unlink($file->getPathname());
}
}
rmdir($path);
}
}
+160
View File
@@ -0,0 +1,160 @@
<?php
// middleware
namespace api\utils;
session_start();
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Slim\App;
use Slim\Exception\HttpInternalServerErrorException;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Psr7\Response;
use Throwable;
use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
/**
* Middleware
* Define all middleware functions
*/
class middleware
{
/**
* Constructor for middleware
* @param App $app - Slim App
*/
public function __construct(App $app)
{
$this->baseMiddleware($app);
$this->sameSiteConfig($app);
$this->jwtAuth($app);
$this->errorHandling($app);
$this->returnAsJSON($app);
}
/**
* Base middleware
* @param App $app - Slim App
*/
public function baseMiddleware(App $app): void
{
$app->addBodyParsingMiddleware();
$app->addRoutingMiddleware();
}
/**
* SameSite Cookie Configuration
* @param App $app - Slim App
*/
public function sameSiteConfig(App $app): void
{
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
$app->add(new SameSiteCookieMiddleware($ssConfig));
}
/**
* Return all responses as JSON
* @param App $app - Slim App
*/
public function returnAsJSON(App $app): void
{
$app->add(function ($request, $handler)
{
$response = $handler->handle($request);
$contentType = $response->getHeaderLine("Content-Type");
if (empty($contentType) || $contentType === "text/html")
{
return $response->withHeader("Content-Type", "application/json");
}
return $response;
});
}
/**
* JWT Authentication
* @param App $app - Slim App
*/
public function jwtAuth(App $app): void
{
$jwtSecret = getSecretKey();
$app->add(new JwtAuthentication([
"rules" => [
new RequestPathRule([
"path" => ["/api/projectData", "/api/timelineData/[a-z]*", "/api/projectImage/[0-9]*", "/api/logout", "/api/blog/[a-z]*"],
"ignore" => ["/api/contact", "/api/userData/login", "/api/userData/changePassword", "/api/blog/newsletter/\S*", "/api/blog/newsletter/unsubscribe/\S*"]
]),
new RequestMethodRule([
"ignore" => ["OPTIONS", "GET"]
])
],
"secret" => $jwtSecret,
"error" => function ($response)
{
session_destroy();
$response->getBody()->write(json_encode(array("status" => "401", "message" =>
"Unauthorized, please provide a valid token")));
return $response->withStatus(401);
}
]));
}
/**
* Error handling
* @param App $app - Slim App
*/
public function errorHandling(App $app): void
{
$app->add(function (ServerRequestInterface $request, RequestHandlerInterface $handler)
{
try
{
return $handler->handle($request);
}
catch (HttpNotFoundException $httpException)
{
$response = (new Response())->withStatus(404);
$response->getBody()->write(json_encode(array("status" => "404", "message" => $request->getUri()->getPath() . " not found")));
return $response;
}
catch (HttpMethodNotAllowedException $httpException)
{
$response = (new Response())->withStatus(405);
$response->getBody()->write(json_encode(array("status" => "405", "message" => "Method not allowed")));
return $response;
}
catch (HttpInternalServerErrorException $exception)
{
$response = (new Response())->withStatus(500);
$response->getBody()->write(json_encode(array("status" => "500", "message" => $exception->getMessage())));
return $response;
}
});
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorMiddleware->setDefaultErrorHandler(function (ServerRequestInterface $request, Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
) use ($app, $errorHandler)
{
$statusCode = $exception->getCode() ?: 500;
// Create a JSON response with the error message
$response = $app->getResponseFactory()->createResponse($statusCode);
$response->getBody()->write(json_encode(['error' => $exception->getMessage()]));
return $response;
});
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace api\utils;
use Slim\App;
interface routesInterface
{
public function createRoutes(App $app): void;
}
+1 -1
View File
@@ -1,4 +1,4 @@
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L] RewriteRule ^ index.html [QSA,L]
+1
View File
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+armasm+arturo+asciidoc+aspnet+asm6502+asmatmel+autohotkey+autoit+avisynth+avro-idl+awk+bash+basic+batch+bbcode+bbj+bicep+birb+bison+bnf+bqn+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+cilkc+cilkcpp+clojure+cmake+cobol+coffeescript+concurnas+csp+cooklang+coq+crystal+css-extras+csv+cue+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gap+gcode+gdscript+gedcom+gettext+gherkin+git+glsl+gn+linker-script+go+go-module+gradle+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+hoon+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keepalived+keyman+kotlin+kumir+kusto+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+magma+makefile+markdown+markup-templating+mata+matlab+maxscript+mel+mermaid+metafont+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+odin+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plant-uml+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+cshtml+jsx+tsx+reason+regex+rego+renpy+rescript+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+stata+iecst+stylus+supercollider+swift+systemd+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+tremor+turtle+twig+typescript+typoscript+unrealscript+uorazor+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+web-idl+wgsl+wiki+wolfram+wren+xeora+xml-doc+xojo+xquery+yaml+yang+zig&plugins=line-numbers+show-language+inline-color+previewers+unescaped-markup+toolbar+copy-to-clipboard+download-button+match-braces */
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
span.inline-color-wrapper{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyIDIiPjxwYXRoIGZpbGw9ImdyYXkiIGQ9Ik0wIDBoMnYySDB6Ii8+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0wIDBoMXYxSDB6TTEgMWgxdjFIMXoiLz48L3N2Zz4=);background-position:center;background-size:110%;display:inline-block;height:1.333ch;width:1.333ch;margin:0 .333ch;box-sizing:border-box;border:1px solid #fff;outline:1px solid rgba(0,0,0,.5);overflow:hidden}span.inline-color{display:block;height:120%;width:120%}
.prism-previewer,.prism-previewer:after,.prism-previewer:before{position:absolute;pointer-events:none}.prism-previewer,.prism-previewer:after{left:50%}.prism-previewer{margin-top:-48px;width:32px;height:32px;margin-left:-16px;z-index:10;opacity:0;-webkit-transition:opacity .25s;-o-transition:opacity .25s;transition:opacity .25s}.prism-previewer.flipped{margin-top:0;margin-bottom:-48px}.prism-previewer:after,.prism-previewer:before{content:'';position:absolute;pointer-events:none}.prism-previewer:before{top:-5px;right:-5px;left:-5px;bottom:-5px;border-radius:10px;border:5px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.5) inset,0 0 10px rgba(0,0,0,.75)}.prism-previewer:after{top:100%;width:0;height:0;margin:5px 0 0 -7px;border:7px solid transparent;border-color:rgba(255,0,0,0);border-top-color:#fff}.prism-previewer.flipped:after{top:auto;bottom:100%;margin-top:0;margin-bottom:5px;border-top-color:rgba(255,0,0,0);border-bottom-color:#fff}.prism-previewer.active{opacity:1}.prism-previewer-angle:before{border-radius:50%;background:#fff}.prism-previewer-angle:after{margin-top:4px}.prism-previewer-angle svg{width:32px;height:32px;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.prism-previewer-angle[data-negative] svg{-webkit-transform:scaleX(-1) rotate(-90deg);-moz-transform:scaleX(-1) rotate(-90deg);-ms-transform:scaleX(-1) rotate(-90deg);-o-transform:scaleX(-1) rotate(-90deg);transform:scaleX(-1) rotate(-90deg)}.prism-previewer-angle circle{fill:transparent;stroke:#2d3438;stroke-opacity:.9;stroke-width:32;stroke-dasharray:0,500}.prism-previewer-gradient{background-image:linear-gradient(45deg,#bbb 25%,transparent 25%,transparent 75%,#bbb 75%,#bbb),linear-gradient(45deg,#bbb 25%,#eee 25%,#eee 75%,#bbb 75%,#bbb);background-size:10px 10px;background-position:0 0,5px 5px;width:64px;margin-left:-32px}.prism-previewer-gradient:before{content:none}.prism-previewer-gradient div{position:absolute;top:-5px;left:-5px;right:-5px;bottom:-5px;border-radius:10px;border:5px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.5) inset,0 0 10px rgba(0,0,0,.75)}.prism-previewer-color{background-image:linear-gradient(45deg,#bbb 25%,transparent 25%,transparent 75%,#bbb 75%,#bbb),linear-gradient(45deg,#bbb 25%,#eee 25%,#eee 75%,#bbb 75%,#bbb);background-size:10px 10px;background-position:0 0,5px 5px}.prism-previewer-color:before{background-color:inherit;background-clip:padding-box}.prism-previewer-easing{margin-top:-76px;margin-left:-30px;width:60px;height:60px;background:#333}.prism-previewer-easing.flipped{margin-bottom:-116px}.prism-previewer-easing svg{width:60px;height:60px}.prism-previewer-easing circle{fill:#2d3438;stroke:#fff}.prism-previewer-easing path{fill:none;stroke:#fff;stroke-linecap:round;stroke-width:4}.prism-previewer-easing line{stroke:#fff;stroke-opacity:.5;stroke-width:2}@-webkit-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@-o-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@-moz-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}.prism-previewer-time:before{border-radius:50%;background:#fff}.prism-previewer-time:after{margin-top:4px}.prism-previewer-time svg{width:32px;height:32px;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.prism-previewer-time circle{fill:transparent;stroke:#2d3438;stroke-opacity:.9;stroke-width:32;stroke-dasharray:0,500;stroke-dashoffset:0;-webkit-animation:prism-previewer-time linear infinite 3s;-moz-animation:prism-previewer-time linear infinite 3s;-o-animation:prism-previewer-time linear infinite 3s;animation:prism-previewer-time linear infinite 3s}
[class*=lang-] script[type='text/plain'],[class*=language-] script[type='text/plain'],script[type='text/plain'][class*=lang-],script[type='text/plain'][class*=language-]{display:block;font:100% Consolas,Monaco,monospace;white-space:pre;overflow:auto}
.token.punctuation.brace-hover,.token.punctuation.brace-selected{outline:solid 1px}.rainbow-braces .token.punctuation.brace-level-1,.rainbow-braces .token.punctuation.brace-level-5,.rainbow-braces .token.punctuation.brace-level-9{color:#e50;opacity:1}.rainbow-braces .token.punctuation.brace-level-10,.rainbow-braces .token.punctuation.brace-level-2,.rainbow-braces .token.punctuation.brace-level-6{color:#0b3;opacity:1}.rainbow-braces .token.punctuation.brace-level-11,.rainbow-braces .token.punctuation.brace-level-3,.rainbow-braces .token.punctuation.brace-level-7{color:#26f;opacity:1}.rainbow-braces .token.punctuation.brace-level-12,.rainbow-braces .token.punctuation.brace-level-4,.rainbow-braces .token.punctuation.brace-level-8{color:#e0e;opacity:1}
/*gruvbox light*/
code[class*=language-],pre[class*=language-]{color:#3c3836;font-family:Consolas,Monaco,"Andale Mono",monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{color:#282828;background:#a89984}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{color:#282828;background:#a89984}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f9f5d7}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em}.token.attr-name,.token.attr-value,.token.attr-value .punctuation,.token.cdata,.token.comment,.token.operator,.token.prolog,.token.punctuation{color:#7c6f64}.token.atrule,.token.boolean,.token.constant,.token.delimiter,.token.important,.token.keyword,.token.property,.token.selector,.token.variable{color:#9d0006}.token.builtin,.token.doctype,.token.function,.token.tag,.token.tag .punctuation{color:#b57614}.token.entity,.token.number,.token.symbol{color:#8f3f71}.token.char,.token.string,.token.url{color:#797403}.token.url{text-decoration:underline}.token.regex{background:#797403}.token.bold{font-weight:700}.token.italic{font-style:italic}.token.inserted{background:#7c6f64}.token.deleted{background:#9d0006}
+197
View File
@@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
id="svg2"
inkscape:export-ydpi="90"
inkscape:export-filename="C:\Users\Ilia\SVG\Atom_icon.png"
viewBox="0 0 285.45 280.91"
inkscape:export-xdpi="90"
version="1.1"
inkscape:version="0.91pre3 r13670"
sodipodi:docname="_svgclean2.svg"
>
<sodipodi:namedview
id="base"
fit-margin-left="10"
inkscape:zoom="1.979899"
borderopacity="1.0"
inkscape:current-layer="layer1"
inkscape:cx="30.185218"
inkscape:cy="330.70792"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:window-maximized="0"
inkscape:snap-bbox="true"
showgrid="false"
fit-margin-right="10"
inkscape:snap-nodes="false"
units="mm"
inkscape:document-units="px"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:snap-smooth-nodes="true"
inkscape:window-width="718"
fit-margin-bottom="10"
inkscape:snap-page="false"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
pagecolor="#ffffff"
inkscape:window-height="645"
fit-margin-top="10"
/>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(-.31824 -771.33)"
>
<g
id="g8434"
transform="matrix(9.7655,0,0,9.7655,-2.8077,-9219.8)"
>
<ellipse
id="path3089"
style="fill:#FFFFFF"
rx="2.0633"
ry="2.0618"
cy="1037.7"
cx="14.936"
/>
<path
id="circle3412"
style="fill:#FFFFFF"
inkscape:connector-curvature="0"
transform="translate(0,1020.4)"
d="m15.045 2.7051v3.3496a11.266 11.258 0 0 1 11.154 11.213h3.3516a14.617 14.606 0 0 0 -14.506 -14.563z"
/>
<path
id="circle3428"
style="fill:#FFFFFF"
inkscape:connector-curvature="0"
transform="translate(0,1020.4)"
d="m15.045 9.4453v2.9492a4.9226 4.919 0 0 1 4.8105 4.873h2.9492a7.8711 7.8654 0 0 0 -7.76 -7.8217z"
/>
</g
>
<g
id="g8430"
transform="matrix(9.7655,0,0,9.7655,-2.8077,-9219.8)"
>
<path
id="path3302"
style="color:#000000;text-indent:0;block-progression:tb;text-decoration-line:none;text-transform:none;fill:#FFFFFF"
inkscape:connector-curvature="0"
transform="translate(0,1020.4)"
d="m14.865 12.807c-3.944 0.0057-7.5137 0.47474-10.127 1.2383-1.3146 0.3841-2.3876 0.844-3.1562 1.375-0.76861 0.5309-1.2617 1.1648-1.2617 1.8906 0 0.7259 0.49311 1.3617 1.2617 1.8926 0.76861 0.5309 1.8417 0.97918 3.1562 1.3633 2.6292 0.7682 6.2246 1.2402 10.197 1.2402 3.9727 0 7.57-0.47204 10.199-1.2402 1.3146-0.3841 2.3857-0.83238 3.1543-1.3633 0.71878-0.49648 1.1813-1.0881 1.2402-1.7559h-0.64453c-0.05963 0.38822-0.35991 0.79958-0.9668 1.2188-0.67801 0.4684-1.6967 0.90955-2.9688 1.2812-2.5442 0.7433-6.0921 1.209-10.014 1.209-3.9216 0-7.4675-0.46568-10.012-1.209-1.2721-0.3717-2.3005-0.81285-2.9785-1.2812-0.67801-0.4683-0.98438-0.92797-0.98438-1.3555 0-0.4274 0.30637-0.89488 0.98438-1.3633 0.67801-0.4683 1.7064-0.90965 2.9785-1.2812 2.5286-0.73883 6.0485-1.2033 9.9414-1.209v-0.65039z"
/>
<circle
id="path8416"
cy="1034.4"
cx="6.1108"
r=".75893"
style="fill:#FFFFFF"
/>
</g
>
<g
id="g8439"
transform="matrix(9.7655,0,0,9.7655,-2.8077,-9219.8)"
>
<g
id="g8426"
>
<path
id="path3304"
d="m14.865 12.236c-0.72049 0.36795-1.4472 0.75012-2.1816 1.1738-3.4404 1.9848-6.3203 4.1911-8.2129 6.1699-0.94628 0.9894-1.6489 1.914-2.0488 2.7578-0.39997 0.8438-0.50968 1.639-0.14648 2.2676s1.1078 0.93201 2.0391 1.0078c0.93131 0.076 2.0893-0.06106 3.4199-0.38476 2.6613-0.6484 6.0127-2.0366 9.4531-4.0215 2.0899-1.2056 3.9354-2.4914 5.5156-3.7598h-1.0293c-1.411 1.0794-3.0286 2.1662-4.8125 3.1953-3.3962 1.9593-6.7001 3.3277-9.2754 3.9551-1.2876 0.3137-2.3914 0.43995-3.2129 0.37305-0.82153-0.067-1.3291-0.31535-1.543-0.68555-0.21387-0.3702-0.16922-0.92367 0.18359-1.668 0.35282-0.7444 1.014-1.6364 1.9297-2.5938 1.8314-1.9149 4.6702-4.0894 8.0664-6.0488 0.62532-0.36075 1.2403-0.68024 1.8555-1v-0.73828z"
style="color:#000000;text-indent:0;block-progression:tb;text-decoration-line:none;text-transform:none;fill:#FFFFFF"
transform="translate(0,1020.4)"
inkscape:connector-curvature="0"
/>
<circle
id="circle8418"
cy="1045.1"
cx="2.8068"
r=".75893"
style="fill:#FFFFFF"
/>
</g
>
<g
id="g8422"
>
<path
id="path3300"
d="m11.682 3.1523c-0.17928-0.012267-0.35779 0.00188-0.5332 0.048828-0.70164 0.1879-1.1876 0.82968-1.502 1.709-0.31431 0.8792-0.47091 2.0283-0.50195 3.3965-0.062086 2.7365 0.4132 6.3316 1.4414 10.166s2.4148 7.1846 3.8379 9.5234c0.71153 1.1695 1.4246 2.087 2.1367 2.6914 0.71217 0.6045 1.4527 0.91642 2.1543 0.72852 0.70164-0.1879 1.1876-0.82783 1.502-1.707 0.31431-0.8793 0.48067-2.034 0.51172-3.4023 0.05491-2.42-0.33654-5.5249-1.1328-8.8594h-0.66797c0.81117 3.3483 1.2082 6.4642 1.1543 8.8418-0.03005 1.3241-0.19344 2.4196-0.4707 3.1953-0.27726 0.7756-0.64933 1.2019-1.0625 1.3125s-0.93818-0.07442-1.5664-0.60742c-0.62822-0.5332-1.3193-1.4036-2.0078-2.5352-1.377-2.2632-2.7448-5.5645-3.7598-9.3496-1.015-3.785-1.482-7.3305-1.4219-9.9785 0.030055-1.324 0.18954-2.4314 0.4668-3.207s0.64152-1.1882 1.0547-1.2988c0.41317-0.1106 0.946 0.062403 1.5742 0.5957 0.6182 0.52469 1.2989 1.3866 1.9766 2.4922v-1.1836c-0.521-0.7474-1.043-1.3562-1.561-1.7957-0.534-0.4534-1.086-0.7406-1.623-0.7774z"
style="color:#000000;text-indent:0;block-progression:tb;text-decoration-line:none;text-transform:none;fill:#FFFFFF"
transform="translate(0,1020.4)"
inkscape:connector-curvature="0"
/>
<circle
id="circle8420"
cx="20.264"
style="fill:#FFFFFF"
r=".75893"
cy="1043.4"
/>
</g
>
</g
>
</g
>
<metadata
id="metadata19"
>
<rdf:RDF
>
<cc:Work
>
<dc:format
>image/svg+xml</dc:format
>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
/>
<cc:license
rdf:resource="http://creativecommons.org/licenses/publicdomain/"
/>
<dc:publisher
>
<cc:Agent
rdf:about="http://openclipart.org/"
>
<dc:title
>Openclipart</dc:title
>
</cc:Agent
>
</dc:publisher
>
</cc:Work
>
<cc:License
rdf:about="http://creativecommons.org/licenses/publicdomain/"
>
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction"
/>
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution"
/>
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks"
/>
</cc:License
>
</rdf:RDF
>
</metadata
>
</svg
>

After

Width:  |  Height:  |  Size: 7.6 KiB

+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="-10 -5 1034 1034" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<path fill="#FFFFFF"
d="M854 175q-27 0 -46 19t-19 45.5t18.5 45t45 18.5t45.5 -18.5t19 -45t-18.5 -45.5t-44.5 -19zM205 192l-34 34q-83 83 -88 154t68 144l82 82q45 46 48.5 78t-33.5 69v0q-16 19 -15.5 44.5t18.5 43.5t43.5 18.5t44.5 -15.5l1 1q25 -25 47 -32t45.5 4.5t53.5 41.5l95 96
q75 74 147.5 70t155.5 -87l33 -34l-71 -72l-18 18q-47 47 -84 47.5t-82 -44.5l-112 -112q-86 -86 -169 -17l-11 -11q35 -42 31.5 -83t-45.5 -82l-100 -101q-31 -31 -40.5 -56.5t1 -51.5t42.5 -59l17 -17zM703 326q-28 0 -46.5 19t-18.5 45.5t18.5 45.5t45 19t45.5 -19
t19 -45.5t-18.5 -45t-44.5 -19.5zM551 477q-27 0 -46 19t-19 45.5t19 45.5t45.5 19t45.5 -19t19 -45.5t-19 -45t-45 -19.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1023 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

+1
View File
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Rohit Pai - Blog</title><meta name="title" content="Rohit Pai - Blog"><meta name="description" content="This is all the blog posts that Rohit Pai has posted. You'll find posts on various topics, mostly on tech but some on various other random topics."><meta name="keywords" content="Blog, all posts, rohit, pai, rohit pai, tech, web development, self-hosting, hosting"><meta name="robots" content="index, follow"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="language" content="English"><meta name="author" content="Rohit Pai"><link rel="stylesheet" href="/blog/css/prism.css"><link rel="stylesheet" href="/blog/css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script><script type="text/javascript" src="https://platform-api.sharethis.com/js/sharethis.js#property=6550cdc47a115e0012964576&product=sop" async="async"></script></head><body><nav><input type="checkbox" id="nav-check"><h1><a href="/" class="link">rohit pai</a></h1><div class="nav-btn"><label for="nav-check"><span></span> <span></span> <span></span></label></div><ul><li><a href="/#about" class="textShadow link">about</a></li><li><a href="/#curriculumVitae" class="textShadow link">cv</a></li><li><a href="/#projects" class="textShadow link">projects</a></li><li><a href="/#contact" class="textShadow link">contact</a></li><li><a href="/blog" class="textShadow link active">blog</a></li></ul></nav><header><div><h1>full stack developer</h1><a href="/#sayHello" class="btn btnPrimary boxShadowIn boxShadowOut">Contact Me</a> <a href="" id="arrow"><i class="fa-solid fa-chevron-down"></i></a></div></header><div class="menuBar"><div class="menu"><ul><li><a href="/blog" class="link active">All posts</a></li><li><a href="/blog/category" class="link">categories</a></li><li><label for="searchField" aria-hidden="true" hidden>search</label> <input type="search" name="search" id="searchField" placeholder="Search..."> <button type="submit" id="searchBtn" class="btn btnPrimary"><i class="fa fa-search"></i></button></li></ul></div></div><main id="main"></main><div class="modal-container" id="cookiePopup"><div class="modal"><div class="modal-content"><h2><i class="fas fa-cookie-bite"></i> Hey I use cookies btw</h2><p>Just to let you know, I use cookies to give you the best experience on my blog. By clicking agree I'll assume that you are happy with it. <a href="/blog/policy/cookie" class="link">Read more</a></p><div class="flexRow"><button class="btn btnPrimary" id="cookieAccept">agree</button></div></div></div></div><footer class="flexRow"><div class="nav"><ul><li><a href="/blog/policy/privacy" class="link">privacy policy</a></li><li><a href="/blog/policy/cookie" class="link">cookie policy</a></li></ul></div><p>&copy; <span id="year"></span> Rohit Pai all rights reserved</p><div class="button"><button id="goBackToTop"><i class="fa-solid fa-chevron-up"></i></button></div></footer><script src="/js/typewriter.js"></script><script src="/blog/js/prism.js"></script><script src="/blog/js/index.js"></script><script id="dsq-count-scr" src="https://rohitpaiportfolio.disqus.com/count.js" async></script></body></html>
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><main class="login"><div id="login" class="container shown"><h1>Login To Editor</h1><form action="" method="POST"><div class="formControl"><label for="username">Username</label> <input type="text" id="username" name="username" required></div><div class="formControl"><label for="password">Password</label> <input type="password" id="password" name="password" required> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="loginError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" id="resetPwd">Reset Password</a></div></form></div><div id="resetPassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="#" method="POST"><div class="formControl"><label for="email">Email</label> <input type="email" id="email" name="email"></div><div class="error hidden" id="resetError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</a></div></form></div><div id="checkResetCode" class="container" style="display: none; transform: translateX(150vw)"><h1>Check Reset Code</h1><form action="#" method="POST"><div class="formControl"><label for="code">Code</label> <input type="text" id="code" name="code"></div><div class="error hidden" id="resetCodeError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</a></div></form></div><div id="changePassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="" method="POST"><div class="formControl"><label for="pass">Password</label> <input type="password" name="pass" id="pass"> <i class="fa-solid fa-eye"></i></div><div class="formControl"><label for="rePass">Password</label> <input type="password" name="rePass" id="rePass"> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="changeError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</a></div></form></div></main><script src="js/index.js"></script></body></html> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><main class="login"><div id="login" class="container shown"><h1>Login To Editor</h1><form action="" method="POST"><div class="formControl"><label for="username">Username</label> <input type="text" id="username" name="username" required></div><div class="formControl passwordControl"><label for="password">Password</label> <input type="password" id="password" name="password" required> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="loginError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="/api/user/login" class="btn btnPrimary boxShadowIn boxShadowOut">Login with Jump Cloud</a> <button type="button" id="resetPwd" class="btn btnPrimary boxShadowIn boxShadowOut">Reset Password</button></div></form></div><div id="resetPassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="#" method="POST"><div class="formControl"><label for="email">Email</label> <input type="email" id="email" name="email"></div><div class="error hidden" id="resetError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</button></div></form></div><div id="checkResetCode" class="container" style="display: none; transform: translateX(150vw)"><h1>Check Reset Code</h1><form action="#" method="POST"><div class="formControl"><label for="code">Code</label> <input type="text" id="code" name="code"></div><div class="error hidden" id="resetCodeError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</button></div></form></div><div id="changePassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="" method="POST"><div class="formControl"><label for="pass">Password</label> <input type="password" name="pass" id="pass"> <i class="fa-solid fa-eye"></i></div><div class="formControl"><label for="rePass">Password</label> <input type="password" name="rePass" id="rePass"> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="changeError"><button class="close" type="button">&times;</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</button></div></form></div></main><script src="js/index.js"></script></body></html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const n=e.af=e.af||{};n.dictionary=Object.assign(n.dictionary||{},{"%0 of %1":"%0 van %1","Align center":"Belyn in die middel","Align left":"Belyn links","Align right":"Belyn regs","Block quote":"Verwysingsaanhaling",Bold:"Vet",Cancel:"Kanselleer",Code:"Bronkode",Find:"Soek","Find and replace":"Soek en vervang","Find in text…":"Soek in teks …","Insert code block":"Voeg bronkodeblok in",Italic:"Kursief",Justify:"Belyn beide kante","Match case":"Hooflettersensitief","Next result":"Volgende resultaat","Plain text":"Gewone skrif","Previous result":"Vorige resultaat","Remove color":"Verwyder kleur","Remove Format":"Verwyder formatering",Replace:"Vervang","Replace all":"Vervang alles","Replace with…":"Vervang met ...","Restore default":"Herstel verstek",Save:"Stoor","Show more items":"Wys meer items","Show options":"Wys opsies",Strikethrough:"Deurstreep",Subscript:"Onderskrif",Superscript:"Boskrif","Text alignment":"Teksbelyning","Text alignment toolbar":"Teksbelyning nutsbank","Text to find must not be empty.":"Soekteks mag nie leeg wees nie.","Tip: Find some text first in order to replace it.":"Wenk: Soek eers 'n bietjie teks om dit te vervang.",Underline:"Onderstreep","Whole words only":"Slegs hele woorde"}),n.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const t=e.ast=e.ast||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"",Aquamarine:"",Black:"",Blue:"",Bold:"Negrina","Break text":"","Bulleted List":"Llista con viñetes","Bulleted list styles toolbar":"",Cancel:"Encaboxar","Caption for image: %0":"","Caption for the image":"","Centered image":"","Change image text alternative":"",Circle:"",Code:"",Decimal:"","Decimal with leading zero":"","Dim grey":"",Disc:"",Downloadable:"","Dropdown toolbar":"","Edit block":"","Edit link":"","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Enter image caption":"","Full size image":"Imaxen a tamañu completu",Green:"",Grey:"",HEX:"","Image resize list":"","Image toolbar":"","image widget":"complementu d'imaxen","In line":"",Insert:"","Insert image":"","Insert image via URL":"",Italic:"Cursiva","Left aligned image":"","Light blue":"","Light green":"","Light grey":"",Link:"Enllazar","Link image":"","Link URL":"URL del enllaz","List properties":"","Lower-latin":"","Lowerroman":"",Next:"","Numbered List":"Llista numberada","Numbered list styles toolbar":"","Open in a new tab":"","Open link in new tab":"",Orange:"",Original:"",Previous:"",Purple:"",Red:"",Redo:"Refacer","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"","Reversed order":"","Rich Text Editor":"Editor de testu arriquecíu","Right aligned image":"",Save:"Guardar","Show more items":"","Side image":"Imaxen llateral",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"",Subscript:"",Superscript:"","Text alternative":"","This link has no URL":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Turquoise:"",Underline:"",Undo:"Desfacer",Unlink:"Desenllazar",Update:"","Update image URL":"","Upload failed":"","Upper-latin":"","Upper-roman":"",White:"","Wrap text":"",Yellow:""}),t.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const i=e.bs=e.bs||{};i.dictionary=Object.assign(i.dictionary||{},{"%0 of %1":"%0 od %1",Accept:"","Align center":"Centrirati","Align left":"Lijevo poravnanje","Align right":"Desno poravnanje",Big:"","Block quote":"Citat",Bold:"Podebljano","Break text":"",Cancel:"Poništi","Caption for image: %0":"","Caption for the image":"","Centered image":"Centrirana slika","Change image text alternative":"Promijeni ALT atribut za sliku","Choose heading":"Odaberi naslov",Code:"Kod",Default:"Zadani","Document colors":"","Edit source":"Uredi izvor","Empty snippet content":"HTML odlomak nema sadžaj","Enter image caption":"Unesi naziv slike",Find:"Pronađi","Find and replace":"Pronađi i zamijeni","Find in text…":"Pronađi u tekstu","Font Background Color":"Boja pozadine","Font Color":"Boja","Font Family":"Font","Font Size":"Veličina fonta","Full size image":"",Heading:"Naslov","Heading 1":"Naslov 1","Heading 2":"Naslov 2","Heading 3":"Naslov 3","Heading 4":"Naslov 4","Heading 5":"Naslov 5","Heading 6":"Naslov 6","Horizontal line":"Horizontalna linija","HTML snippet":"HTML odlomak",Huge:"","Image resize list":"Lista veličina slike","Image toolbar":"","image widget":"","In line":"",Insert:"Umetni","Insert code block":"Umetni kod blok","Insert HTML":"Umetni HTML","Insert image":"Umetni sliku","Insert image via URL":"Umetni sliku preko URLa",Italic:"Zakrivljeno",Justify:"","Left aligned image":"Lijevo poravnata slika","Match case":"Podudaranje","Next result":"","No preview available":"Pregled nedostupan",Original:"Original",Paragraph:"Paragraf","Paste raw HTML here...":"Zalijepi HTML ovdje...","Plain text":"Tekst","Previous result":"Prethodni rezultat","Remove color":"Ukloni boju",Replace:"Zamijeni","Replace all":"Zamijeni sve","Replace with…":"Zamijeni sa...","Resize image":"Promijeni veličinu slike","Resize image to %0":"","Resize image to the original size":"Postavi originalnu veličinu slike","Restore default":"Vrati na zadano","Right aligned image":"Desno poravnata slika",Save:"Sačuvaj","Save changes":"Sačuvaj izmjene","Show more items":"Prikaži više stavki","Show options":"Prikaži opcije","Side image":"",Small:"",Strikethrough:"Precrtano",Subscript:"",Superscript:"","Text alignment":"Poravnanje teksta","Text alignment toolbar":"Traka za poravnanje teksta","Text alternative":"ALT atribut","Text to find must not be empty.":"Unesite tekst za pretragu.",Tiny:"","Tip: Find some text first in order to replace it.":"",Underline:"Podcrtano",Update:"Ažuriraj","Update image URL":"Ažuriraj URL slike","Upload failed":"Učitavanje slike nije uspjelo","Whole words only":"Samo cijele riječi","Wrap text":"Prelomi tekst"}),i.getPluralForm=function(e){return e%10==1&&e%100!=11?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const t=e["en-gb"]=e["en-gb"]||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"%0 of %1",Aquamarine:"Aquamarine",Black:"Black","Block quote":"Block quote",Blue:"Blue",Bold:"Bold","Break text":"","Bulleted List":"Bulleted List",Cancel:"Cancel","Caption for image: %0":"","Caption for the image":"","Centered image":"Centred image","Change image text alternative":"Change image text alternative","Characters: %0":"Characters: %0","Choose heading":"Choose heading",Column:"Column","Decrease indent":"Decrease indent","Delete column":"Delete column","Delete row":"Delete row","Dim grey":"Dim grey",Downloadable:"Downloadable","Dropdown toolbar":"","Edit block":"Edit block","Edit link":"Edit link","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Enter image caption":"Enter image caption","Full size image":"Full size image",Green:"Green",Grey:"Grey","Header column":"Header column","Header row":"Header row",Heading:"Heading","Heading 1":"Heading 1","Heading 2":"Heading 2","Heading 3":"Heading 3","Heading 4":"Heading 4","Heading 5":"Heading 5","Heading 6":"Heading 6",HEX:"","Image toolbar":"","image widget":"Image widget","In line":"","Increase indent":"Increase indent","Insert column left":"Insert column left","Insert column right":"Insert column right","Insert image":"Insert image","Insert media":"Insert media","Insert row above":"Insert row above","Insert row below":"Insert row below","Insert table":"Insert table",Italic:"Italic","Left aligned image":"Left aligned image","Light blue":"Light blue","Light green":"Light green","Light grey":"Light grey",Link:"Link","Link URL":"Link URL","Media URL":"Media URL","media widget":"Media widget","Merge cell down":"Merge cell down","Merge cell left":"Merge cell left","Merge cell right":"Merge cell right","Merge cell up":"Merge cell up","Merge cells":"Merge cells",Next:"Next","Numbered List":"Numbered List","Open in a new tab":"Open in a new tab","Open link in new tab":"Open link in new tab","Open media in new tab":"",Orange:"Orange",Paragraph:"Paragraph","Paste the media URL in the input.":"Paste the media URL in the input.",Previous:"Previous",Purple:"Purple",Red:"Red",Redo:"Redo","Rich Text Editor":"Rich Text Editor","Right aligned image":"Right aligned image",Row:"Row",Save:"Save","Select column":"","Select row":"","Show more items":"","Side image":"Side image","Split cell horizontally":"Split cell horizontally","Split cell vertically":"Split cell vertically","Table toolbar":"","Text alternative":"Text alternative","The URL must not be empty.":"The URL must not be empty.","This link has no URL":"This link has no URL","This media URL is not supported.":"This media URL is not supported.","Tip: Paste the URL into the content to embed faster.":"Tip: Paste the URL into the content to embed faster.","Toggle caption off":"","Toggle caption on":"",Turquoise:"Turquoise",Undo:"Undo",Unlink:"Unlink","Upload failed":"Upload failed","Upload in progress":"Upload in progress",White:"White","Words: %0":"Words: %0","Wrap text":"",Yellow:"Yellow"}),t.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const i=e.eo=e.eo||{};i.dictionary=Object.assign(i.dictionary||{},{"%0 of %1":"",Aquamarine:"",Black:"",Blue:"",Bold:"grasa","Break text":"","Bulleted List":"Bula Listo","Bulleted list styles toolbar":"",Cancel:"Nuligi","Caption for image: %0":"","Caption for the image":"","Centered image":"","Change image text alternative":"Ŝanĝu la alternativan tekston de la bildo","Choose heading":"Elektu ĉapon",Circle:"",Code:"",Decimal:"","Decimal with leading zero":"","Dim grey":"",Disc:"",Downloadable:"","Dropdown toolbar":"","Edit block":"","Edit link":"","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Enter image caption":"Skribu klarigon pri la bildo","Full size image":"Bildo kun reala dimensio",Green:"",Grey:"",Heading:"Ĉapo","Heading 1":"Ĉapo 1","Heading 2":"Ĉapo 2","Heading 3":"Ĉapo 3","Heading 4":"","Heading 5":"","Heading 6":"",HEX:"","Image resize list":"","Image toolbar":"","image widget":"bilda fenestraĵo","In line":"",Insert:"","Insert image":"Enmetu bildon","Insert image via URL":"",Italic:"kursiva","Left aligned image":"","Light blue":"","Light green":"","Light grey":"",Link:"Ligilo","Link image":"","Link URL":"URL de la ligilo","List properties":"","Lower-latin":"","Lowerroman":"",Next:"","Numbered List":"Numerita Listo","Numbered list styles toolbar":"","Open in a new tab":"","Open link in new tab":"",Orange:"",Original:"",Paragraph:"Paragrafo",Previous:"",Purple:"",Red:"",Redo:"Refari","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"","Reversed order":"","Rich Text Editor":"Redaktilo de Riĉa Teksto","Right aligned image":"",Save:"Konservi","Show more items":"","Side image":"Flanka biildo",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"",Subscript:"",Superscript:"","Text alternative":"Alternativa teksto","This link has no URL":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Turquoise:"",Underline:"",Undo:"Malfari",Unlink:"Malligi",Update:"","Update image URL":"","Upload failed":"","Upper-latin":"","Upper-roman":"",White:"","Wrap text":"",Yellow:""}),i.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
+1
View File
@@ -0,0 +1 @@
!function(e){const r=e["es-co"]=e["es-co"]||{};r.dictionary=Object.assign(r.dictionary||{},{"%0 of %1":"%0 de %1","Align center":"Centrar","Align left":"Alinear a la izquierda","Align right":"Alinear a la derecha","Block quote":"Cita de bloque",Bold:"Negrita",Cancel:"Cancelar","Characters: %0":"Caracteres: %0",Code:"Código","Insert code block":"Insertar bloque de código",Italic:"Cursiva",Justify:"Justificar","Plain text":"Texto plano","Remove color":"Quitar color","Restore default":"Restaurar valores predeterminados",Save:"Guardar","Show more items":"Mostrar más elementos",Strikethrough:"Tachado",Subscript:"Subíndice",Superscript:"Superíndice","Text alignment":"Alineación de texto","Text alignment toolbar":"Herramientas de alineación de texto",Underline:"Subrayado","Upload in progress":"Carga en progreso","Words: %0":"Palabras: %0"}),r.getPluralForm=function(e){return 1==e?0:0!=e&&e%1e6==0?1:2}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const i=e.eu=e.eu||{};i.dictionary=Object.assign(i.dictionary||{},{"%0 of %1":"",Aquamarine:"",Black:"","Block quote":"Aipua",Blue:"",Bold:"Lodia","Break text":"","Bulleted List":"Buletdun zerrenda","Bulleted list styles toolbar":"",Cancel:"Utzi","Caption for image: %0":"","Caption for the image":"","Centered image":"Zentratutako irudia","Change image text alternative":"Aldatu irudiaren ordezko testua","Choose heading":"Aukeratu izenburua",Circle:"",Code:"Kodea",Decimal:"","Decimal with leading zero":"","Dim grey":"",Disc:"",Downloadable:"","Dropdown toolbar":"","Edit block":"","Edit link":"","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Enter image caption":"Sartu irudiaren epigrafea","Full size image":"Tamaina osoko irudia",Green:"",Grey:"",Heading:"Izenburua","Heading 1":"Izenburua 1","Heading 2":"Izenburua 2","Heading 3":"Izenburua 3","Heading 4":"","Heading 5":"","Heading 6":"",HEX:"","Image resize list":"","Image toolbar":"","image widget":"irudi widgeta","In line":"",Insert:"","Insert image":"Txertatu irudia","Insert image via URL":"",Italic:"Etzana","Left aligned image":"Ezkerrean lerrokatutako irudia","Light blue":"","Light green":"","Light grey":"",Link:"Esteka","Link image":"","Link URL":"Estekaren URLa","List properties":"","Lower-latin":"","Lowerroman":"",Next:"","Numbered List":"Zenbakidun zerrenda","Numbered list styles toolbar":"","Open in a new tab":"","Open link in new tab":"",Orange:"",Original:"",Paragraph:"Paragrafoa",Previous:"",Purple:"",Red:"",Redo:"Berregin","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"","Reversed order":"","Rich Text Editor":"Testu aberastuaren editorea","Right aligned image":"Eskuinean lerrokatutako irudia",Save:"Gorde","Show more items":"","Side image":"Alboko irudia",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"",Subscript:"",Superscript:"","Text alternative":"Ordezko testua","This link has no URL":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Turquoise:"",Underline:"Azpimarra",Undo:"Desegin",Unlink:"Desestekatu",Update:"","Update image URL":"","Upload failed":"Kargatzeak huts egin du","Upper-latin":"","Upper-roman":"",White:"","Wrap text":"",Yellow:""}),i.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(o){const e=o.gu=o.gu||{};e.dictionary=Object.assign(e.dictionary||{},{"%0 of %1":"","Block quote":" વિચાર ટાંકો",Bold:"ઘાટુ - બોલ્ડ્",Cancel:"",Code:"",Italic:"ત્રાંસુ - ઇટલિક્","Remove color":"","Restore default":"",Save:"","Show more items":"",Strikethrough:"",Subscript:"",Superscript:"",Underline:"નીચે લિટી - અન્ડરલાઇન્"}),e.getPluralForm=function(o){return 1!=o}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const a=e.jv=e.jv||{};a.dictionary=Object.assign(a.dictionary||{},{"%0 of %1":"%0 saking %1",Accept:"","Align center":"Rata tengah","Align left":"Rata kiwa","Align right":"Rata tengen",Big:"Ageng","Blue marker":"Penandha biru",Bold:"Kandhel","Break text":"","Bulleted List":"","Bulleted list styles toolbar":"",Cancel:"Batal","Caption for image: %0":"","Caption for the image":"","Centered image":"Gambar ing tengah","Change image text alternative":"","Choose heading":"","Choose language":"Pilih basa",Circle:"Bunder",Code:"Kode",Decimal:"","Decimal with leading zero":"",Default:"Default",Disc:"Kaset","Document colors":"Warni dokumen","Edit source":"","Empty snippet content":"","Enter image caption":"",Find:"Pados","Find and replace":"Pados lan gantos","Find in text…":"Pados ing seratan","Font Background Color":"Warni Latar Aksara","Font Color":"Warni aksara","Font Family":"Jinising Aksara","Font Size":"Ukuran aksara","Full size image":"Gambar ukuran kebak","Green marker":"Panandha ijem","Green pen":"Pen ijem",Heading:"","Heading 1":"","Heading 2":"","Heading 3":"","Heading 4":"","Heading 5":"","Heading 6":"",Highlight:"Sorot","Horizontal line":"Garis horisontal","HTML object":"Obyek HTML","HTML snippet":"",Huge:"Langkung ageng","Image resize list":"","Image toolbar":"","image widget":"","In line":"",Insert:"Tambah","Insert code block":"","Insert HTML":"Tambahaken HTML","Insert image":"Tambahaken gambar","Insert image via URL":"Tambah gambar saking URL",Italic:"Miring",Justify:"Rata kiwa tengen",Language:"Basa","Left aligned image":"Gambar ing kiwa","List properties":"","Lower-latin":"","Lowerroman":"","Match case":"Samikaken aksara","Next result":"Kasil salajengipun","No preview available":"","Numbered List":"","Numbered list styles toolbar":"",Original:"Asli",Paragraph:"","Paste raw HTML here...":"","Pink marker":"Penandha abrit jambon","Plain text":"Seratan biasa","Previous result":"Kasil saderengipun","Red pen":"Penandha abrit","Remove color":"Busek warni","Remove highlight":"Busek sorot","Remove language":"Busek basa",Replace:"Gantos","Replace all":"Gantos sedaya","Replace with…":"Gantos kaliyan...","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"Mangsulaken default","Reversed order":"Dipunwangsul","Right aligned image":"Gambar ing tengen",Save:"Rimat","Save changes":"","Show more items":"Tampilaken langkung kathah","Show options":"Tampilaken pilihan","Side image":"",Small:"Alit",Square:"Kotak","Start at":"Wiwit saking","Start index must be greater than 0.":"",Strikethrough:"Seratan dicoret",Subscript:"",Superscript:"","Text alignment":"Perataan seratan","Text alignment toolbar":"","Text alternative":"","Text highlight toolbar":"","Text to find must not be empty.":"Seratan ingkang dipunpadosi mboten angsal kosong.",Tiny:"Langkung alit","Tip: Find some text first in order to replace it.":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Underline:"Garis ngandhap",Update:"","Update image URL":"","Upload failed":"","Upper-latin":"","Upper-roman":"","Whole words only":"Sedayaning ukanten","Wrap text":"","Yellow marker":"Panandha jene"}),a.getPluralForm=function(e){return 0}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
+1
View File
@@ -0,0 +1 @@
!function(n){const t=n.kk=n.kk||{};t.dictionary=Object.assign(t.dictionary||{},{"Align center":"Ортадан туралау","Align left":"Солға туралау","Align right":"Оңға туралау",Justify:"","Text alignment":"Мәтінді туралау","Text alignment toolbar":"Мәтінді туралау құралдар тақтасы"}),t.getPluralForm=function(n){return 1!=n}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
+1
View File
@@ -0,0 +1 @@
!function(e){const t=e.km=e.km||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"","Align center":"តម្រឹម​កណ្ដាល","Align left":"តម្រឹម​ឆ្វេង","Align right":"តម្រឹម​ស្ដាំ",Aquamarine:"",Black:"","Block quote":"ប្លុក​ពាក្យ​សម្រង់",Blue:"",Bold:"ដិត","Break text":"","Bulleted List":"បញ្ជី​ជា​ចំណុច","Bulleted list styles toolbar":"",Cancel:"បោះបង់","Caption for image: %0":"","Caption for the image":"","Centered image":"","Change image text alternative":"","Choose heading":"ជ្រើសរើស​ក្បាលអត្ថបទ",Circle:"",Code:"កូដ",Decimal:"","Decimal with leading zero":"","Dim grey":"",Disc:"",Downloadable:"","Dropdown toolbar":"","Edit block":"","Edit link":"","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Enter image caption":"បញ្ចូល​ពាក្យ​ពណ៌នា​រូបភាព","Full size image":"រូបភាព​ពេញ​ទំហំ",Green:"",Grey:"",Heading:"ក្បាលអត្ថបទ","Heading 1":"ក្បាលអត្ថបទ 1","Heading 2":"ក្បាលអត្ថបទ 2","Heading 3":"ក្បាលអត្ថបទ 3","Heading 4":"","Heading 5":"","Heading 6":"",HEX:"","Image resize list":"","Image toolbar":"","image widget":"វិដជិត​រូបភាព","In line":"",Insert:"","Insert image":"បញ្ចូល​រូបភាព","Insert image via URL":"",Italic:"ទ្រេត",Justify:"តម្រឹម​សងខាង","Left aligned image":"","Light blue":"","Light green":"","Light grey":"",Link:"តំណ","Link image":"","Link URL":"URL តំណ","List properties":"","Lower-latin":"","Lowerroman":"",Next:"","Numbered List":"បញ្ជី​ជា​លេខ","Numbered list styles toolbar":"","Open in a new tab":"","Open link in new tab":"",Orange:"",Original:"",Paragraph:"កថាខណ្ឌ",Previous:"",Purple:"",Red:"",Redo:"ធ្វើ​វិញ","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"","Reversed order":"","Rich Text Editor":"កម្មវិធី​កែសម្រួល​អត្ថបទ​សម្បូរបែប","Right aligned image":"",Save:"រក្សាទុ","Show more items":"","Side image":"រូបភាព​នៅ​ខាង",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"ឆូតកណ្ដាល",Subscript:"អក្សរ​តូចក្រោម",Superscript:"អក្សរ​តូចលើ","Text alignment":"ការ​តម្រឹម​អក្សរ","Text alignment toolbar":"របារ​ឧបករណ៍​តម្រឹម​អក្សរ","Text alternative":"","This link has no URL":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Turquoise:"",Underline:"គូស​បន្ទាត់​ក្រោម",Undo:"លែង​ធ្វើ​វិញ",Unlink:"ផ្ដាច់​តំណ",Update:"","Update image URL":"","Upload failed":"អាប់ឡូត​មិនបាន","Upper-latin":"","Upper-roman":"",White:"","Wrap text":"",Yellow:""}),t.getPluralForm=function(e){return 0}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
+1
View File
@@ -0,0 +1 @@
!function(e){const i=e.kn=e.kn||{};i.dictionary=Object.assign(i.dictionary||{},{"%0 of %1":"",Aquamarine:"",Black:"","Block quote":"‍‍‍‍ಗುರುತಿಸಲಾದ ‍‍ಉಲ್ಲೇಖ",Blue:"",Bold:"‍ದಪ್ಪ","Break text":"","Bulleted List":"‍‍ಬುಲೆಟ್ ಪಟ್ಟಿ","Bulleted list styles toolbar":"",Cancel:"ರದ್ದುಮಾಡು","Caption for image: %0":"","Caption for the image":"","Centered image":"","Change image text alternative":"‍ಚಿತ್ರದ ಬದಲಿ ಪಠ್ಯ ಬದಲಾಯಿಸು","Choose heading":"ಶೀರ್ಷಿಕೆ ಆಯ್ಕೆಮಾಡು",Circle:"",Code:"",Decimal:"","Decimal with leading zero":"","Dim grey":"",Disc:"",Downloadable:"","Dropdown toolbar":"","Edit block":"","Edit link":"","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Enter image caption":"‍ಚಿತ್ರದ ಶೀರ್ಷಿಕೆ ಸೇರಿಸು","Full size image":"‍ಪೂರ್ಣ ‍‍ಅಳತೆಯ ಚಿತ್ರ",Green:"",Grey:"",Heading:"ಶೀರ್ಷಿಕೆ","Heading 1":"ಶೀರ್ಷಿಕೆ 1","Heading 2":"ಶೀರ್ಷಿಕೆ 2","Heading 3":"ಶೀರ್ಷಿಕೆ 3","Heading 4":"","Heading 5":"","Heading 6":"",HEX:"","Image resize list":"","Image toolbar":"","image widget":"‍ಚಿತ್ರ ವಿಜೆಟ್","In line":"",Insert:"","Insert image":"","Insert image via URL":"",Italic:"‍ಇಟಾಲಿಕ್","Left aligned image":"","Light blue":"","Light green":"","Light grey":"",Link:"‍ಕೊಂಡಿ","Link image":"","Link URL":"‍ಕೊಂಡಿ ಸಂಪರ್ಕಿಸು","List properties":"","Lower-latin":"","Lowerroman":"",Next:"","Numbered List":"‍ಸಂಖ್ಯೆಯ ಪಟ್ಟಿ‍","Numbered list styles toolbar":"","Open in a new tab":"","Open link in new tab":"",Orange:"",Original:"",Paragraph:"ಪ್ಯಾರಾಗ್ರಾಫ್",Previous:"",Purple:"",Red:"",Redo:"‍ಮತ್ತೆ ಮಾಡು","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"","Reversed order":"","Rich Text Editor":"‍ಸಮೃದ್ಧ ಪಠ್ಯ ಸಂಪಾದಕ‍‍","Right aligned image":"",Save:"ಉಳಿಸು","Show more items":"","Side image":"‍ಪಕ್ಕದ ಚಿತ್ರ",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"",Subscript:"",Superscript:"","Text alternative":"‍ಪಠ್ಯದ ಬದಲಿ","This link has no URL":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Turquoise:"",Underline:"",Undo:"‍ರದ್ದು",Unlink:"‍ಕೊಂಡಿ ತೆಗೆ",Update:"","Update image URL":"","Upload failed":"","Upper-latin":"","Upper-roman":"",White:"","Wrap text":"",Yellow:""}),i.getPluralForm=function(e){return e>1}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(o){const r=o.oc=o.oc||{};r.dictionary=Object.assign(r.dictionary||{},{"%0 of %1":"",Bold:"Gras",Cancel:"Anullar",Code:"",Italic:"Italica","Remove color":"","Restore default":"",Save:"Enregistrar","Show more items":"",Strikethrough:"",Subscript:"",Superscript:"",Underline:""}),r.getPluralForm=function(o){return o>1}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const t=e.si=e.si||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"",Bold:"තදකුරු","Break text":"","Bulleted List":"බුලටිත ලැයිස්තුව","Bulleted list styles toolbar":"",Cancel:"","Caption for image: %0":"","Caption for the image":"","Centered image":"","Change image text alternative":"",Circle:"",Code:"",Decimal:"","Decimal with leading zero":"",Disc:"","Enter image caption":"","Full size image":"","Image resize list":"","Image toolbar":"","image widget":"","In line":"",Insert:"","Insert image":"පින්තූරය ඇතුල් කරන්න","Insert image via URL":"",Italic:"ඇලකුරු","Left aligned image":"","List properties":"","Lower-latin":"","Lowerroman":"","Numbered List":"අංකිත ලැයිස්තුව","Numbered list styles toolbar":"",Original:"",Redo:"නැවත කරන්න","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Restore default":"","Reversed order":"","Right aligned image":"",Save:"","Show more items":"","Side image":"",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"",Subscript:"",Superscript:"","Text alternative":"","To-do List":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lowerlatin list style":"","Toggle the lowerroman list style":"","Toggle the square list style":"","Toggle the upperlatin list style":"","Toggle the upperroman list style":"",Underline:"",Undo:"අහෝසි කරන්න",Update:"","Update image URL":"","Upload failed":"උඩුගත කිරීම අසාර්ථක විය","Upper-latin":"","Upper-roman":"","Wrap text":""}),t.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
!function(e){const o=e.sl=e.sl||{};o.dictionary=Object.assign(o.dictionary||{},{"%0 of %1":"",Accept:"","Align cell text to the bottom":"","Align cell text to the center":"","Align cell text to the left":"","Align cell text to the middle":"","Align cell text to the right":"","Align cell text to the top":"","Align center":"Sredinska poravnava","Align left":"Poravnava levo","Align right":"Poravnava desno","Align table to the left":"","Align table to the right":"",Alignment:"",Aquamarine:"Akvamarin",Background:"",Big:"Veliko",Black:"Črna","Block quote":"Blokiraj citat",Blue:"Modra","Blue marker":"Modra oznaka",Bold:"Krepko",Border:"",Cancel:"Prekliči","Cell properties":"","Center table":"","Choose heading":"Izberi naslov",Code:"Koda",Color:"","Color picker":"",Column:"",Dashed:"",Default:"Privzeto","Delete column":"","Delete row":"","Dim grey":"Temno siva",Dimensions:"","Document colors":"Barve dokumenta",Dotted:"",Double:"","Dropdown toolbar":"","Edit block":"","Edit source":"Uredi izvorno kodo","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Empty snippet content":"","Enter table caption":"","Font Background Color":"Barva ozadja pisave","Font Color":"Barva pisave","Font Family":"Vrsta oz. tip pisave","Font Size":"Velikost pisave",Green:"Zelena","Green marker":"Zelena oznaka","Green pen":"Zeleno pisalo",Grey:"Siva",Groove:"","Header column":"","Header row":"",Heading:"Naslov","Heading 1":"Naslov 1","Heading 2":"Naslov 2","Heading 3":"Naslov 3","Heading 4":"Naslov 4","Heading 5":"Naslov 5","Heading 6":"Naslov 6",Height:"",HEX:"",Highlight:"Označi","Horizontal line":"Vodoravna črta","Horizontal text alignment toolbar":"","HTML snippet":"HTML izsek",Huge:"Ogromno","Insert column left":"","Insert column right":"","Insert HTML":"Vstavi HTML","Insert row above":"","Insert row below":"","Insert table":"Vstavi tabelo",Inset:"",Italic:"Poševno",Justify:"Postavi na sredino","Justify cell text":"","Light blue":"Svetlo modra","Light green":"Svetlo zelena","Light grey":"Svetlo siva","Merge cell down":"","Merge cell left":"","Merge cell right":"","Merge cell up":"","Merge cells":"",Next:"","No preview available":"",None:"",Orange:"Oranžna",Outset:"",Padding:"",Paragraph:"Odstavek","Paste raw HTML here...":"Prilepi HTML kodo ...","Pink marker":"Rožnata oznaka",Previous:"",Purple:"Vijolična",Red:"Rdeča","Red pen":"Rdeče pisalo","Remove color":"Odstrani barvo","Remove highlight":"Odstrani oznako","Restore default":"","Rich Text Editor":"",Ridge:"",Row:"",Save:"Shrani","Save changes":"Shrani spremembe","Select column":"","Select row":"","Show more items":"",Small:"Majhna",Solid:"","Split cell horizontally":"","Split cell vertically":"",Strikethrough:"Prečrtano",Style:"",Subscript:"Naročnik",Superscript:"Nadpis","Table alignment toolbar":"","Table cell text alignment":"","Table properties":"","Table toolbar":"","Text alignment":"Poravnava besedila","Text alignment toolbar":"Orodna vrstica besedila","Text highlight toolbar":"Orodna vrstica označevanja",'The color is invalid. Try "#FF0000" or "rgb(255,0,0)" or "red".':"",'The value is invalid. Try "10px" or "2em" or simply "2".':"",Tiny:"Drobna","Toggle caption off":"","Toggle caption on":"",Turquoise:"Turkizna",Underline:"Podčrtaj","Vertical text alignment toolbar":"",White:"Bela",Width:"",Yellow:"Rumena","Yellow marker":"Rumena oznaka"}),o.getPluralForm=function(e){return e%100==1?0:e%100==2?1:e%100==3||e%100==4?2:3}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

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