├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── _vApp ├── .htaccess ├── add.vue ├── assets │ └── style.scss ├── components │ ├── Drawer.vue │ ├── File.vue │ ├── GeoComplete.vue │ ├── Header.vue │ ├── LeftColumn.vue │ ├── Listing.vue │ ├── MediaDialog.vue │ ├── Paginate.vue │ ├── RichTextarea.vue │ ├── SEO.vue │ └── Table.vue ├── css │ ├── app.scss │ └── main.css ├── pages │ ├── Index.vue │ ├── layout.vue │ ├── login.vue │ ├── page │ │ ├── add.vue │ │ ├── index.vue │ │ └── list.vue │ ├── post │ │ ├── add.vue │ │ ├── index.vue │ │ └── list.vue │ └── postCategory │ │ ├── add.vue │ │ └── list.vue ├── plugins │ ├── Axios.js │ └── Vuetify.js ├── routes.js ├── store │ └── index.js └── vApp.js ├── composer.json ├── config ├── adlara.php └── auth.php ├── controllers ├── AdminController.php └── AdminControllers │ ├── AdminUserController.php │ ├── MediaController.php │ ├── PageController.php │ ├── PostCategoryController.php │ └── PostController.php ├── database ├── factories │ ├── PostCategoryFactory.php │ └── PostFactory.php ├── migrations │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2018_01_18_112915_create_users_table.php │ ├── 2018_01_19_053208_create_admin_users_table.php │ ├── 2018_01_19_053208_create_page_table.php │ ├── 2018_01_19_053514_create_admin_password_reset_table.php │ ├── 2018_01_19_054151_create_component_table.php │ ├── 2019_01_21_051412_post_category.php │ ├── 2019_01_21_051423_post.php │ ├── 2019_01_21_051441_post_category_assign.php │ ├── 2019_01_21_051657_media.php │ └── 2019_01_21_051833_media_image_size.php └── seeds │ └── PostSeeder.php ├── middleware ├── AdminUser.php └── VerifyCSRFToken.php ├── objects ├── AdminUser.php ├── IDB.php ├── Media.php ├── MediaImageSize.php ├── Page.php ├── Post.php ├── PostCategory.php └── PostCategoryAssigned.php ├── package.json ├── providers ├── RouteServiceProvider.php └── kernel.php ├── routes └── admin.php ├── src ├── Bootable.php ├── RoutesProvider.php └── helper.php ├── views ├── admin │ └── dashboard.blade.php └── front │ └── welcome.blade.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | rvm: 3 | - 7.2 4 | - 7.1 5 | - 7.0 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jigesh Raval 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AdLara Bootstrap 2 | 3 | Laravel VueJS/Vuetify Powered admin, booting up required components that separates Admin and Front and provides rich tools such as Media Library 4 | 5 | # What will this bootstraping do? (List of Functions) 6 | 7 | - Ready to go Laravel/Vue/Vuetify Admin 8 | - Sample Blog, ready to extend or use 9 | - Provides Multiple Authentication for the Front end and the Back end (Admin) 10 | - Creates Separate Controllers Folders (AdminControllers and FrontControllers) 11 | - Separate Route files, for admin -> admin.php and for front-end web.php 12 | - Separte views for admin and front end so that the application remains organized and flows well 13 | - Media Management: Manage static assets of your application through database. It provides boiler plate to record every upload in the database. Of course, it has Rich Media Library built with VueJs (https://vuejs.org) and Uppy.io (https://uppy.io/). 14 | - The media library reduces the time consuming tasks of creating uploading functionality and manage it and speed-up the other tasks 15 | - Image resizing (Powered by http://image.intervention.io/) 16 | 17 | # Installation 18 | 19 | ``` bash 20 | composer require jigeshraval/laravel-admin-dashboard 21 | ``` 22 | 23 | # Installation Steps 24 | 25 | 1. composer require jigeshraval/laravel-admin-dashboard 26 | 2. Add "JigeshRaval\Bootable::class" in the providers array in config/app.php 27 | 3. Make sure database credentials are added in .env file and database is connected with the Laravel Application 28 | 4. Delete all the migrations from database/migrations folder 29 | 5. php artisan vendor:publish --tag=adlarafullsetup --force 30 | 6. php artisan migrate 31 | 7. php artisan storage:link (For Media and Static Resources) 32 | 8. npm install 33 | 9. npm run watch (for the dev mode) or npm run production (if you're ready to deploy) 34 | 10. Now go to http://127.0.0.1:8000/admin and you will be able to see login screen, use jigesh@jigeshraval.com and password: adlaraera1 for your initial login 35 | 36 | # This step is only if you want database seeding to be done 37 | 11. php artisan db:seed --class=PostSeeder 38 | 39 | # Documentation 40 | 41 | - https://jigeshraval.com/en/blog/laravel-admin-dashboard 42 | -------------------------------------------------------------------------------- /_vApp/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Handle Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /_vApp/add.vue: -------------------------------------------------------------------------------- 1 | 75 | 148 | -------------------------------------------------------------------------------- /_vApp/assets/style.scss: -------------------------------------------------------------------------------- 1 | #_mainDrawer { 2 | overflow: visible; 3 | height: 100vh !important; 4 | position: sticky; 5 | top: 0 !important; 6 | overflow: visible; 7 | } 8 | 9 | #_sideList .v-list-group__items { 10 | border-left: 5px solid; 11 | } 12 | 13 | #_sideList.v-list--dense .v-list-group__items .v-list-item .v-list-item__title { 14 | font-size: 14px; 15 | color: #555; 16 | } 17 | 18 | #_sideList.v-list--dense .v-list-item .v-list-item__title { 19 | font-size: 16px; 20 | } -------------------------------------------------------------------------------- /_vApp/components/Drawer.vue: -------------------------------------------------------------------------------- 1 | 103 | 104 | 145 | 146 | -------------------------------------------------------------------------------- /_vApp/components/File.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 146 | 147 | 186 | -------------------------------------------------------------------------------- /_vApp/components/GeoComplete.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 99 | -------------------------------------------------------------------------------- /_vApp/components/Header.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 72 | -------------------------------------------------------------------------------- /_vApp/components/LeftColumn.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 33 | -------------------------------------------------------------------------------- /_vApp/components/Listing.vue: -------------------------------------------------------------------------------- 1 | 101 | 102 | 283 | -------------------------------------------------------------------------------- /_vApp/components/MediaDialog.vue: -------------------------------------------------------------------------------- 1 | 106 | 107 | 320 | 321 | 472 | -------------------------------------------------------------------------------- /_vApp/components/Paginate.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 47 | -------------------------------------------------------------------------------- /_vApp/components/RichTextarea.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 46 | -------------------------------------------------------------------------------- /_vApp/components/SEO.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | -------------------------------------------------------------------------------- /_vApp/components/Table.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | -------------------------------------------------------------------------------- /_vApp/css/app.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jigeshraval/laravel-admin-dashboard/3856bd3aabe2f60d7095b0923633a706bdc3de90/_vApp/css/app.scss -------------------------------------------------------------------------------- /_vApp/css/main.css: -------------------------------------------------------------------------------- 1 | .full { 2 | max-width: 100%; 3 | width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /_vApp/pages/Index.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 99 | 100 | 299 | -------------------------------------------------------------------------------- /_vApp/pages/layout.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 101 | 102 | 301 | -------------------------------------------------------------------------------- /_vApp/pages/login.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 113 | -------------------------------------------------------------------------------- /_vApp/pages/page/add.vue: -------------------------------------------------------------------------------- 1 | 84 | 173 | -------------------------------------------------------------------------------- /_vApp/pages/page/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /_vApp/pages/page/list.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /_vApp/pages/post/add.vue: -------------------------------------------------------------------------------- 1 | 143 | 256 | -------------------------------------------------------------------------------- /_vApp/pages/post/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /_vApp/pages/post/list.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /_vApp/pages/postCategory/add.vue: -------------------------------------------------------------------------------- 1 | 76 | 173 | -------------------------------------------------------------------------------- /_vApp/pages/postCategory/list.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 38 | -------------------------------------------------------------------------------- /_vApp/plugins/Axios.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | import store from '../store/index.js' 4 | var ax = axios; 5 | var axiosx = axios.create({ 6 | baseURL: 'http://127.0.0.1:8000/' + ADMIN_API_ROUTE 7 | }) 8 | Vue.prototype.$axiosx = axiosx; 9 | Vue.prototype.$axios = ax; 10 | axiosx.interceptors.request.use(function (config) { 11 | store.commit('loading', true); 12 | // const token = cookie.get(__TOKEN_KEY__); 13 | // if (token != null) { 14 | // config.headers.Authorization = Bearer ${token}; 15 | // } 16 | return config; 17 | }, function (err) { 18 | return Promise.reject(err); 19 | }); 20 | ax.interceptors.request.use(function (config) { 21 | store.commit('loading', true); 22 | // const token = cookie.get(__TOKEN_KEY__); 23 | // if (token != null) { 24 | // config.headers.Authorization = Bearer ${token}; 25 | // } 26 | return config; 27 | }, function (err) { 28 | return Promise.reject(err); 29 | }); 30 | axiosx.interceptors.response.use(function (res) { 31 | 32 | console.log(res); 33 | 34 | store.commit('loading', false); 35 | 36 | var snacktext = null; 37 | 38 | if (res.data && res.data.snackText) { 39 | var snackText = res.data.snackText 40 | } 41 | 42 | if (snackText) { 43 | store.commit('snackbar', { status: true, text: snackText }); 44 | } 45 | 46 | // Do something with response data 47 | return res; 48 | }, function (error) { 49 | 50 | store.commit('loading', false); 51 | 52 | var res = error.response; 53 | var errors = res.data.errors.name; 54 | 55 | if (errors && errors[0]) { 56 | 57 | store.commit('snackbar', { 58 | status: true, 59 | text: errors[0] 60 | }); 61 | 62 | } 63 | }); 64 | ax.interceptors.response.use(function (response) { 65 | 66 | console.log(response); 67 | store.commit('loading', false); 68 | // Do something with response data 69 | return response; 70 | 71 | }, function (response) { 72 | 73 | store.commit('loading', false); 74 | var res = error.response; 75 | console.log(res); 76 | 77 | }); 78 | export default ax; 79 | -------------------------------------------------------------------------------- /_vApp/plugins/Vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import '@mdi/font/css/materialdesignicons.min.css' 4 | 5 | import Vuetify, { 6 | VDatePicker, 7 | VApp, 8 | VCard, 9 | VCardText, 10 | VCardTitle, 11 | VCardActions, 12 | VForm, 13 | VTextField, 14 | VTextarea, 15 | VBtn, 16 | VAppBar, 17 | VAppBarNavIcon, 18 | VContainer, 19 | VNavigationDrawer, 20 | VDivider, 21 | VList, 22 | VListItem, 23 | VListItemIcon, 24 | VListItemTitle, 25 | VListItemGroup, 26 | VIcon, 27 | VListItemAvatar, 28 | VImg, 29 | VListItemContent, 30 | VListItemSubtitle, 31 | VListItemAction, 32 | VToolbar, 33 | VToolbarTitle, 34 | VMenu, 35 | VSimpleTable, 36 | VPagination, 37 | VSelect, 38 | VSwitch, 39 | VProgressLinear, 40 | VFlex, 41 | VLayout, 42 | VCheckbox, 43 | VExpansionPanels, 44 | VExpansionPanel, 45 | VExpansionPanelHeader, 46 | VExpansionPanelContent, 47 | VDialog, 48 | VAlert, 49 | VRadio, 50 | VRadioGroup, 51 | VCombobox, 52 | VAutocomplete, 53 | VTabs, 54 | VTab, 55 | VTabItem, 56 | VTabsItems, 57 | VTabsSlider, 58 | VCol, 59 | VRow, 60 | VListGroup, 61 | VSnackbar 62 | } from "vuetify/lib" 63 | 64 | Vue.use(Vuetify, { 65 | components: { 66 | VDatePicker, 67 | VApp, 68 | VDialog, 69 | VAlert, 70 | VListGroup, 71 | VCol, 72 | VRow, 73 | VTabs, 74 | VTab, 75 | VTabItem, 76 | VTabsItems, 77 | VTabsSlider, 78 | VRadio, 79 | VAutocomplete, 80 | VCombobox, 81 | VRadioGroup, 82 | VExpansionPanels, 83 | VExpansionPanel, 84 | VExpansionPanelHeader, 85 | VExpansionPanelContent, 86 | VLayout, 87 | VFlex, 88 | VCheckbox, 89 | VCard, 90 | VCardText, 91 | VCardTitle, 92 | VCardActions, 93 | VForm, 94 | VTextField, 95 | VTextarea, 96 | VBtn, 97 | VAppBar, 98 | VAppBarNavIcon, 99 | VContainer, 100 | VNavigationDrawer, 101 | VDivider, 102 | VList, 103 | VListItem, 104 | VListItemIcon, 105 | VListItemTitle, 106 | VListItemGroup, 107 | VIcon, 108 | VListItemAvatar, 109 | VImg, 110 | VListItemContent, 111 | VListItemSubtitle, 112 | VListItemAction, 113 | VToolbar, 114 | VToolbarTitle, 115 | VMenu, 116 | VSimpleTable, 117 | VPagination, 118 | VSelect, 119 | VSwitch, 120 | VProgressLinear, 121 | VSnackbar 122 | } 123 | }) 124 | 125 | export default new Vuetify({ 126 | icons: { 127 | iconfont: 'mdi' 128 | }, 129 | theme: { 130 | dark: false, 131 | }, 132 | themes: { 133 | light: { 134 | primary: "#ed4b3f", 135 | secondary: "#b0bec5", 136 | accent: "#8c9eff", 137 | error: "#b71c1c", 138 | }, 139 | }, 140 | }) 141 | -------------------------------------------------------------------------------- /_vApp/routes.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | Vue.use(VueRouter) 5 | 6 | //Components for routes 7 | 8 | import LoginScreen from './pages/login' 9 | import Pages from './pages/page/list' 10 | import PageAdd from './pages/page/add' 11 | 12 | import PostCategoryAdd from './pages/postCategory/add.vue' 13 | import PostCategoryEdit from './pages/postCategory/add.vue' 14 | import PostCategoryList from './pages/postCategory/list.vue' 15 | 16 | import PostAdd from './pages/post/add.vue' 17 | import PostEdit from './pages/post/add.vue' 18 | import PostList from './pages/post/index.vue' 19 | 20 | const routes = [ 21 | 22 | { 23 | path: '/login', 24 | component: LoginScreen 25 | }, 26 | { 27 | path: '/page/add', 28 | component: PageAdd 29 | }, 30 | { 31 | path: '/page/edit/:id', 32 | component: PageAdd 33 | }, 34 | { 35 | path: '/pages', 36 | component: Pages 37 | }, 38 | { 39 | path: '/post/edit/:id', 40 | component: PostEdit 41 | }, 42 | { 43 | path: '/posts', 44 | component: PostList 45 | }, 46 | { 47 | path: '/post/add', 48 | component: PostAdd 49 | }, 50 | { 51 | path: '/blog/category/edit/:id', 52 | component: PostCategoryEdit 53 | }, 54 | { 55 | path: '/blog/category', 56 | component: PostCategoryList 57 | }, 58 | { 59 | path: '/blog/category/add', 60 | component: PostCategoryAdd 61 | } 62 | 63 | ]; 64 | 65 | const router = new VueRouter({ 66 | mode: 'history', 67 | routes: routes, 68 | base: ADMIN_APP_ROUTE 69 | }) 70 | 71 | export default router; -------------------------------------------------------------------------------- /_vApp/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex); 5 | 6 | const store = new Vuex.Store({ 7 | state: { 8 | loading: false, 9 | test: 'jigesh', 10 | snackbar: { 11 | status: false, 12 | text: '', 13 | color: 'error' 14 | }, 15 | api: 'http://127.0.0.1:8000', 16 | media_dialog: false, 17 | selectedMedia: [], 18 | selectedMediaIds: [], 19 | selectMultipleMedia: true, 20 | mediaSelectionFinished: false, 21 | mediaType: 'Image', 22 | drawerVisibility: true 23 | }, 24 | mutations: { 25 | setDrawerVisibility(state, val) { 26 | state.drawerVisibility = val; 27 | }, 28 | setMediaType(state, type) { 29 | state.mediaType = type; 30 | }, 31 | snackbar(state, data) { 32 | 33 | state.snackbar.status = data.status; 34 | 35 | if (!data.text) { 36 | data.text = ''; 37 | } 38 | 39 | state.snackbar.text = data.text; 40 | 41 | if (data && data.status && data.status == 'success') { 42 | state.snackbar.color = "success"; 43 | } 44 | 45 | }, 46 | loading(state, status) { 47 | state.loading = status; 48 | }, 49 | setSelectMultipleMedia(state, data) { 50 | state.selectMultipleMedia = data; 51 | }, 52 | mediaSelectionFinished(state, data) { 53 | state.mediaSelectionFinished = data; 54 | }, 55 | setSelectedMedia(state, array) { 56 | state.selectedMedia = array; 57 | }, 58 | setSelectedMediaIds(state, array) { 59 | state.selectedMediaIds = array; 60 | }, 61 | media_dialog(state, status) { 62 | state.media_dialog = status; 63 | }, 64 | } 65 | }); 66 | 67 | Vue.prototype.$store = store; 68 | 69 | export default store; 70 | -------------------------------------------------------------------------------- /_vApp/vApp.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from './plugins/Axios' 3 | import vuetify from './plugins/Vuetify' 4 | import routes from './routes' 5 | import vuex from './store/index.js' 6 | 7 | //Default page or layout 8 | import layout from './pages/layout' 9 | 10 | const app = new Vue({ 11 | vuex, 12 | router: routes, 13 | axios, 14 | vuetify, 15 | el: '#dApp', 16 | render: h => h(layout) 17 | }); -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jigeshraval/laravel-admin-dashboard", 3 | "description": "Laravel VueJS/Vuetify Powered admin, booting up required components that separates Admin and Front and provides rich tools such as Media Library", 4 | "type": "library", 5 | "authors": [ 6 | { 7 | "name": "Jigesh Raval", 8 | "email": "jigesh@jigeshraval.com" 9 | } 10 | ], 11 | "autoload": { 12 | "psr-4": { 13 | "JigeshRaval\\": "src/" 14 | } 15 | }, 16 | "require": { 17 | "intervention/image": "^2.5" 18 | }, 19 | "license": "MIT" 20 | } 21 | -------------------------------------------------------------------------------- /config/adlara.php: -------------------------------------------------------------------------------- 1 | 'admin', 21 | 22 | 'app_scope' => 'front' 23 | 24 | ]; -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | 'hash' => false, 48 | ], 49 | 50 | 'admin_user' => [ 51 | 'driver' => 'session', 52 | 'provider' => 'admin_user' 53 | ] 54 | ], 55 | 56 | /* 57 | |-------------------------------------------------------------------------- 58 | | User Providers 59 | |-------------------------------------------------------------------------- 60 | | 61 | | All authentication drivers have a user provider. This defines how the 62 | | users are actually retrieved out of your database or other storage 63 | | mechanisms used by this application to persist your user's data. 64 | | 65 | | If you have multiple user tables or models you may configure multiple 66 | | sources which represent each model / table. These sources may then 67 | | be assigned to any extra authentication guards you have defined. 68 | | 69 | | Supported: "database", "eloquent" 70 | | 71 | */ 72 | 73 | 'providers' => [ 74 | 'users' => [ 75 | 'driver' => 'eloquent', 76 | 'model' => App\User::class, 77 | ], 78 | 79 | 'admin_user' => [ 80 | 'driver' => 'eloquent', 81 | 'model' => App\Objects\AdminUser::class, 82 | ], 83 | 84 | // 'users' => [ 85 | // 'driver' => 'database', 86 | // 'table' => 'users', 87 | // ], 88 | ], 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Resetting Passwords 93 | |-------------------------------------------------------------------------- 94 | | 95 | | You may specify multiple password reset configurations if you have more 96 | | than one user table or model in the application and you want to have 97 | | separate password reset settings based on the specific user types. 98 | | 99 | | The expire time is the number of minutes that the reset token should be 100 | | considered valid. This security feature keeps tokens short-lived so 101 | | they have less time to be guessed. You may change this as needed. 102 | | 103 | */ 104 | 105 | 'passwords' => [ 106 | 'users' => [ 107 | 'provider' => 'users', 108 | 'table' => 'password_resets', 109 | 'expire' => 60, 110 | 'throttle' => 60, 111 | ], 112 | ], 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Password Confirmation Timeout 117 | |-------------------------------------------------------------------------- 118 | | 119 | | Here you may define the amount of seconds before a password confirmation 120 | | times out and the user is prompted to re-enter their password via the 121 | | confirmation screen. By default, the timeout lasts for three hours. 122 | | 123 | */ 124 | 125 | 'password_timeout' => 10800, 126 | 127 | ]; 128 | -------------------------------------------------------------------------------- /controllers/AdminController.php: -------------------------------------------------------------------------------- 1 | input()) 21 | )->each(function ($value, $filter) { 22 | 23 | if (!$value) { 24 | return; 25 | } 26 | 27 | $filter = str_replace('-', '.', $filter); 28 | 29 | if (!in_array($filter, $this->skip_filtering)) { 30 | 31 | $this->filter = true; 32 | $this->filter_search[] = [$filter, 'LIKE', '%' . $value . '%']; 33 | 34 | } 35 | }); 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /controllers/AdminControllers/AdminUserController.php: -------------------------------------------------------------------------------- 1 | initProcessFilter(); 17 | 18 | $admin_user = AdminUser::select('id', 'name', 'email') 19 | ->orderBy('id', 'desc'); 20 | 21 | if ($this->filter) { 22 | $admin_user->where($this->filter_search); 23 | } 24 | 25 | $this->obj = $admin_user->paginate($this->paginate); 26 | 27 | $keys = [ 28 | 'id' => [ 29 | 'text' => 'ID', 30 | 'filter' => true 31 | ], 32 | 'name' => [ 33 | 'text' => 'Name', 34 | 'filter' => true 35 | ], 36 | 'email' => [ 37 | 'text' => 'Email', 38 | 'filter' => true 39 | ] 40 | ]; 41 | 42 | return array( 43 | 'obj' => $this->obj, 44 | 'keys' => $keys 45 | ); 46 | } 47 | 48 | public function initContentRegister($id = null) 49 | { 50 | $this->obj = new AdminUser; 51 | 52 | if ($id) { 53 | $this->obj = AdminUser::find($id); 54 | } 55 | 56 | 57 | return array( 58 | 'employee' => $this->obj 59 | ); 60 | } 61 | 62 | public function initProcessRegister(Request $request, $id = null) 63 | { 64 | $data = $request->all(); 65 | if ($data['password'] != $data['password_confirmation']) { 66 | return json('error', 'Password and Confirm Passwords are not matching'); 67 | } 68 | 69 | if (isset($data['password']) && $data['password'] && strlen($data['password']) < 6) { 70 | return json('error', 'Too short password'); 71 | } 72 | 73 | $getUser = AdminUser::where('email', $data['email'])->first(); 74 | 75 | if ($getUser) { 76 | $admin_user = $getUser; 77 | } 78 | 79 | if ($getUser && !$id) { 80 | return json('error', 'Admin User already exists'); 81 | } 82 | 83 | $admin_user->name = $data['name']; 84 | $admin_user->email = $data['email']; 85 | $admin_user->password = Hash::make($data['password']); 86 | $admin_user->save(); 87 | 88 | if (!$id) { 89 | return json('redirect', 'edit/' . $admin_user->id); 90 | } 91 | 92 | return json('success', t('Admin User updated')); 93 | } 94 | 95 | public function guard() 96 | { 97 | return Auth::guard('admin_user'); 98 | } 99 | 100 | public function initProcessDelete($id = null) 101 | { 102 | $obj = AdminUser::find($id); 103 | 104 | if ($obj) { 105 | 106 | $obj->delete(); 107 | 108 | } 109 | 110 | return redirect(route('admin_user.list')); 111 | } 112 | 113 | public function initProcessLogin() 114 | { 115 | $login_success = Auth::guard('admin_user')->attempt([ 116 | 'email' => request()->input('email'), 117 | 'password' => request()->input('password') 118 | ], request()->input('keep_active')); 119 | 120 | if ($login_success) { 121 | return array( 122 | 'status' => 'success', 123 | 'message' => 'Authenticated' 124 | ); 125 | } 126 | 127 | return array( 128 | 'status' => 'error', 129 | 'message' => 'Authentication failed' 130 | ); 131 | } 132 | 133 | public function initProcessLogout() 134 | { 135 | Auth::guard('admin_user')->logout(); 136 | 137 | $admin_route = config('adlara.admin_route') . '/app/login'; 138 | 139 | $url = url($admin_route); 140 | 141 | return redirect($url); 142 | } 143 | 144 | public function initProcessCheckLogin() 145 | { 146 | if (Auth::guard('admin_user')->check()) { 147 | return array( 148 | 'status' => 'success' 149 | ); 150 | } 151 | 152 | return response('Unauthenticated', 401); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /controllers/AdminControllers/MediaController.php: -------------------------------------------------------------------------------- 1 | file('files') 16 | )->each(function ($file) { 17 | 18 | $media = new Media; 19 | $media->store($file); 20 | 21 | }); 22 | 23 | } 24 | 25 | public function initProcessListing() 26 | { 27 | $type = request()->input('type'); 28 | $media = new Media; 29 | 30 | if ($type == 'pdf') { 31 | $type = 'application'; 32 | } 33 | 34 | $list = $media 35 | ->orderBy('id', 'desc') 36 | ->where('type', $type); 37 | 38 | if ($type == 'application') { 39 | $list->where('format', 'pdf'); 40 | } 41 | 42 | $list = $list->paginate(24); 43 | 44 | if (count($list)) { 45 | foreach ($list as $key => $media) { 46 | $file = $media->retrieve(250, 250, false); 47 | if ($file) { 48 | $list[$key]['url'] = $file; 49 | } 50 | } 51 | } 52 | 53 | return $list; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /controllers/AdminControllers/PageController.php: -------------------------------------------------------------------------------- 1 | initProcessFilter(); 14 | 15 | return response()->json([ 16 | 'obj' => $this->getList(), 17 | 'keys' => $this->getFilterKeys() 18 | ]); 19 | } 20 | 21 | protected function getList() 22 | { 23 | $page = Page::select('id', 'name', 'url', 'status') 24 | ->orderBy('id', 'desc'); 25 | 26 | if ($this->filter) { 27 | $page->where($this->filter_search); 28 | } 29 | 30 | return $page->paginate($this->paginate); 31 | } 32 | 33 | protected function getFilterKeys() 34 | { 35 | return [ 36 | 'id' => [ 37 | 'text' => 'ID', 38 | 'filter' => true 39 | ], 40 | 'name' => [ 41 | 'text' => 'Name', 42 | 'filter' => true 43 | ], 44 | 'url' => [ 45 | 'text' => 'Url', 46 | 'filter' => true 47 | ], 48 | 'status' => [ 49 | 'text' => 'Status', 50 | 'filter' => false, 51 | 'switch' => true 52 | ] 53 | ]; 54 | } 55 | 56 | public function initContentCreate($id = null) 57 | { 58 | $actions = array( 59 | 'heading' => 'Page', 60 | 'slug' => '/pages' 61 | ); 62 | 63 | $this->obj = new Page; 64 | 65 | if ($id) { 66 | $this->obj = $this->obj->find($id); 67 | $actions = array( 68 | 'heading' => 'Page : ' . $this->obj->name, 69 | 'slug' => '/pages' 70 | ); 71 | } 72 | 73 | return array( 74 | 'page' => $this->obj, 75 | 'actions' => $actions 76 | ); 77 | } 78 | 79 | public function initProcessCreate($id = null) 80 | { 81 | $this->obj = new Page; 82 | 83 | if ($id) { 84 | $this->obj = $this->obj->find($id); 85 | } 86 | 87 | if (request()->input('status')) { 88 | $status = 1; 89 | } else { 90 | $status = 0; 91 | } 92 | 93 | $data = $this->obj; 94 | $data->name = request()->input('name'); 95 | $data->url = \Str::slug(request()->input('url')); 96 | $data->content = protectedString(request()->input('content')); 97 | $data->status = $status; 98 | $data->meta_title = request()->input('meta_title'); 99 | $data->meta_description = request()->input('meta_description'); 100 | $data->save(); 101 | 102 | if (!$id) { 103 | return json('redirect', 'edit/' . $data->id); 104 | } 105 | 106 | return json('success', t('Page Updated')); 107 | } 108 | 109 | 110 | public function initProcessDelete() 111 | { 112 | $component = request()->input('component'); 113 | $id = request()->input('id'); 114 | 115 | if ($component == 'employee') { 116 | $component = 'admin_user'; 117 | } 118 | 119 | if (!$id) { 120 | return true; 121 | } 122 | 123 | if (!$component) { 124 | return true; 125 | } 126 | 127 | $component = \Str::camel($component); 128 | $class = '\App\\Objects\\' . $component; 129 | 130 | $c = $class::find($id); 131 | $c->delete(); 132 | 133 | return json('success', 'Deleted successfully'); 134 | } 135 | 136 | public function initProcessChangeStatus() 137 | { 138 | $component = request()->input('component'); 139 | $id = request()->input('id'); 140 | $column = request()->input('column'); 141 | $value = request()->input('value'); 142 | 143 | $component = ucwords(\Str::camel($component)); 144 | $class = '\App\\Objects\\' . $component; 145 | 146 | $c = $class::find($id); 147 | 148 | if ($c) { 149 | 150 | $c->updateColumn($column, $value); 151 | 152 | return array( 153 | 'status' => 'success', 154 | 'text' => 'Changes updated' 155 | ); 156 | } 157 | 158 | return array( 159 | 'status' => 'error', 160 | 'text' => 'Object could not be initialised' 161 | ); 162 | 163 | 164 | if (!$c->approved && !$c->status) { 165 | $first = true; 166 | } 167 | 168 | $c->$column = $status; 169 | $c->save(); 170 | 171 | return json('success', ucfirst($column) . ' updated'); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /controllers/AdminControllers/PostCategoryController.php: -------------------------------------------------------------------------------- 1 | initProcessFilter(); 14 | 15 | $post_category = PostCategory::select('id', 'title', 'status') 16 | ->orderBy('id', 'desc'); 17 | 18 | if ($this->filter) { 19 | $post_category->where($this->filter_search); 20 | } 21 | 22 | $this->obj = $post_category->paginate($this->paginate); 23 | 24 | $keys = [ 25 | 'id' => [ 26 | 'text' => 'ID', 27 | 'filter' => true 28 | ], 29 | 'title' => [ 30 | 'text' => 'Title', 31 | 'filter' => true 32 | ], 33 | 'status' => [ 34 | 'text' => 'Status', 35 | 'filter' => false, 36 | 'switch' => true 37 | ] 38 | ]; 39 | 40 | return array( 41 | 'obj' => $this->obj, 42 | 'keys' => $keys 43 | ); 44 | } 45 | 46 | public function initContentCreate($id = null) 47 | { 48 | $this->obj = new PostCategory; 49 | if ($id) { 50 | $this->obj = $this->obj->find($id); 51 | } 52 | 53 | return array( 54 | 'post_category' => $this->obj 55 | ); 56 | } 57 | 58 | public function initProcessCreate($id = null) 59 | { 60 | 61 | $this->obj = new PostCategory; 62 | 63 | if ($id) { 64 | $this->obj = $this->obj->find($id); 65 | } 66 | 67 | if (request()->input('status')) { 68 | $status = 1; 69 | } else { 70 | $status = 0; 71 | } 72 | 73 | $data = $this->obj; 74 | $data->title = request()->input('name'); 75 | $data->url = \Str::slug(request()->input('url')); 76 | $data->status = $status; 77 | $data->meta_title = request()->input('meta_title'); 78 | $data->meta_description = request()->input('meta_description'); 79 | $data->save(); 80 | 81 | if (!$id) { 82 | return json('redirect', 'edit/' . $data->id); 83 | } 84 | 85 | return json('success', t('Post Category updated')); 86 | } 87 | 88 | public function initProcessDelete($id = null) 89 | { } 90 | } 91 | -------------------------------------------------------------------------------- /controllers/AdminControllers/PostController.php: -------------------------------------------------------------------------------- 1 | initProcessFilter(); 13 | 14 | $post = Post::select('id', 'title', 'published') 15 | ->orderBy('id', 'desc'); 16 | 17 | if ($this->filter) { 18 | $post->where($this->filter_search); 19 | } 20 | 21 | $this->obj = $post->paginate($this->paginate); 22 | 23 | $keys = [ 24 | 'id' => [ 25 | 'text' => 'ID', 26 | 'filter' => true 27 | ], 28 | 'title' => [ 29 | 'text' => 'Title', 30 | 'filter' => true 31 | ], 32 | 'published' => [ 33 | 'text' => 'Published', 34 | 'filter' => false, 35 | 'switch' => true 36 | ] 37 | ]; 38 | 39 | return array( 40 | 'obj' => $this->obj, 41 | 'keys' => $keys 42 | ); 43 | } 44 | 45 | public function initContentCreate($id = null) 46 | { 47 | $this->obj = new Post; 48 | $this->obj->selected_category = array(); 49 | 50 | if ($id) { 51 | $this->obj = $this->obj->find($id); 52 | $this->obj->selected_category = $this->obj->post_category()->pluck('post_category.id')->toArray(); 53 | 54 | if ($this->obj->image) { 55 | $this->obj->image->url = $this->obj->image->retrieve(250, 250, false); 56 | } 57 | } 58 | 59 | $this->obj->category = PostCategory::select('id', 'title as name') 60 | ->orderBy('id', 'desc') 61 | ->get(); 62 | 63 | return array( 64 | 'post' => $this->obj 65 | ); 66 | 67 | } 68 | 69 | public function initProcessCreate($id = null) 70 | { 71 | $this->obj = new Post; 72 | 73 | if ($id) { 74 | $this->obj = $this->obj->find($id); 75 | } 76 | 77 | if (request()->input('display_home')) { 78 | $display_home = 1; 79 | } else { 80 | $display_home = 0; 81 | } 82 | 83 | if (request()->input('main_post')) { 84 | $main_post = 1; 85 | } else { 86 | $main_post = 0; 87 | } 88 | 89 | $data = $this->obj; 90 | $data->title = ucwords(request()->input('title')); 91 | $data->url = request()->input('url'); 92 | $data->content = protectedString(request()->input('content')); 93 | $data->id_author = \Auth::guard('admin_user')->user()->id; 94 | $data->meta_title = request()->input('meta_title'); 95 | $data->meta_description = request()->input('meta_description'); 96 | $data->id_media = request()->input('id_media'); 97 | $data->post_date = request()->input('post_date'); 98 | $data->published = (bool) request()->input('published'); 99 | $data->save(); 100 | 101 | if (count(request()->input('category'))) { 102 | 103 | if ($id) { 104 | \App\Objects\PostCategoryAssigned::where('id_post', $data->id)->forceDelete(); 105 | } 106 | 107 | foreach (request()->input('category') as $input) { 108 | $re = new \App\Objects\PostCategoryAssigned; 109 | $re->id_category = $input; 110 | $re->id_post = $data->id; 111 | $re->save(); 112 | } 113 | } 114 | 115 | if (!$id) { 116 | return json('redirect', 'edit/' . $data->id); 117 | } 118 | 119 | return json('success', t('Post updated')); 120 | } 121 | 122 | public function initProcessDelete($id = null) 123 | { 124 | 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /database/factories/PostCategoryFactory.php: -------------------------------------------------------------------------------- 1 | define(PostCategory::class, function (Faker $faker) { 9 | $title = $faker->sentence; 10 | return [ 11 | 'title' => $title, 12 | 'url' => \Str::slug($title), 13 | 'meta_title' => $title, 14 | 'meta_description' => $title 15 | ]; 16 | }); -------------------------------------------------------------------------------- /database/factories/PostFactory.php: -------------------------------------------------------------------------------- 1 | define(Post::class, function (Generator $faker) { 11 | 12 | $title = $faker->sentence; 13 | 14 | $paragraph = ''; 15 | 16 | for ($x = 1; $x <= 5; $x++) { 17 | $paragraph .= '

' . $faker->paragraph(10) . '

'; 18 | } 19 | 20 | return [ 21 | 'title' => $title, 22 | 'url' => \Str::slug($title), 23 | 'content' => $paragraph, 24 | 'meta_title' => $title, 25 | 'meta_description' => $title, 26 | 'post_date' => date('Y-m-d h:i:s'), 27 | 'published' => 0 28 | ]; 29 | }); 30 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 23 | $table->string('email', 250)->index(); 24 | $table->string('token'); 25 | $table->timestamp('created_at')->nullable(); 26 | $table->engine = 'InnoDB'; 27 | }); 28 | } 29 | 30 | /** 31 | * Reverse the migrations. 32 | * 33 | * @return void 34 | */ 35 | public function down() 36 | { 37 | Schema::hasTable('password_resets'); 38 | Schema::dropIfExists('password_resets'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/2018_01_18_112915_create_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->string('email'); 20 | $table->string('password'); 21 | $table->string('mobile')->nullable(); 22 | $table->rememberToken(); 23 | $table->timestamps(); 24 | $table->softDeletes(); 25 | $table->engine = 'InnoDB'; 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::hasTable('users'); 37 | Schema::dropIfExists('users'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/migrations/2018_01_19_053208_create_admin_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 19 | $table->string('name'); 20 | $table->string('email'); 21 | $table->string('password'); 22 | $table->string('mobile')->nullable(); 23 | $table->rememberToken(); 24 | $table->timestamps(); 25 | $table->softDeletes(); 26 | $table->engine = 'InnoDB'; 27 | }); 28 | 29 | $data = [ 30 | 'name' => 'Jigesh Raval', 31 | 'email' => 'jigesh@jigeshraval.com', 32 | 'password' => Hash::make('adlaraera1') 33 | ]; 34 | \Illuminate\Support\Facades\DB::table('admin_users')->insert($data); 35 | } 36 | 37 | /** 38 | * Reverse the migrations. 39 | * 40 | * @return void 41 | */ 42 | public function down() 43 | { 44 | Schema::dropIfExists('admin_users'); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /database/migrations/2018_01_19_053208_create_page_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->longText('content')->nullable(); 20 | $table->string('url')->nullable(); 21 | $table->integer('status')->unsigned()->default(0); 22 | $table->integer('id_featured_image')->unsigned()->nullable(); 23 | $table->integer('id_lang')->unsigned()->default(1); 24 | $table->string('meta_title')->nullable(); 25 | $table->string('meta_description')->nullable(); 26 | $table->timestamps(); 27 | $table->softDeletes(); 28 | $table->engine = 'InnoDB'; 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | * 35 | * @return void 36 | */ 37 | public function down() 38 | { 39 | Schema::dropIfExists('page'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /database/migrations/2018_01_19_053514_create_admin_password_reset_table.php: -------------------------------------------------------------------------------- 1 | string('email', 250)->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | $table->engine = 'InnoDB'; 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('admin_password_reset'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/migrations/2018_01_19_054151_create_component_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->string('table'); 20 | $table->string('variable'); 21 | $table->string('slug'); 22 | $table->string('controller'); 23 | $table->integer('is_front_create')->unsigned(); 24 | $table->integer('is_front_view')->unsigned(); 25 | $table->integer('is_front_list')->unsigned(); 26 | $table->integer('is_admin_create')->unsigned(); 27 | $table->integer('is_admin_list')->unsigned(); 28 | $table->integer('is_admin_delete')->unsigned(); 29 | $table->integer('is_login_needed')->unsigned()->nullable(); 30 | $table->integer('is_meta_needed')->unsigned(); 31 | $table->timestamps(); 32 | $table->softDeletes(); 33 | $table->engine = 'InnoDB'; 34 | }); 35 | 36 | Schema::create('component_fields', function (Blueprint $table) { 37 | $table->increments('id'); 38 | $table->integer('id_component')->unsigned(); 39 | $table->string('field_name'); 40 | $table->string('field_text'); 41 | $table->string('column_type'); 42 | $table->string('input_type'); 43 | $table->integer('use_in_listing')->unsigned(); 44 | $table->integer('is_fillable')->unsigned(); 45 | $table->integer('required')->unsigned(); 46 | $table->integer('default')->nullable(); 47 | $table->string('class')->nullable(); 48 | $table->string('relationship_type')->nullable(); 49 | $table->string('reference_name')->nullable(); 50 | $table->string('relational_component_name')->nullable(); 51 | $table->string('foreign_key')->nullable(); 52 | $table->string('local_key')->nullable(); 53 | $table->string('mediator_table')->nullable(); 54 | $table->string('mediator_table_key')->nullable(); 55 | $table->timestamps(); 56 | $table->softDeletes(); 57 | $table->engine = 'InnoDB'; 58 | }); 59 | } 60 | 61 | /** 62 | * Reverse the migrations. 63 | * 64 | * @return void 65 | */ 66 | public function down() 67 | { 68 | Schema::dropIfExists('component'); 69 | Schema::dropIfExists('component_fields'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /database/migrations/2019_01_21_051412_post_category.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('title')->default()->nullable(); 19 | $table->string('url')->default()->nullable(); 20 | $table->integer('id_media')->default()->nullable(); 21 | $table->integer('id_lang')->default()->nullable(); 22 | $table->integer('status')->default()->nullable(); 23 | $table->string('meta_title')->default()->nullable(); 24 | $table->string('meta_description')->default()->nullable(); 25 | $table->timestamps(); 26 | $table->softDeletes(); 27 | $table->engine = 'InnoDB'; 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | * 34 | * @return void 35 | */ 36 | public function down() 37 | { 38 | Schema::dropIfExists('post_category'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/2019_01_21_051423_post.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('title')->nullable(); 19 | $table->string('url')->nullable(); 20 | $table->longText('content')->nullable(); 21 | $table->integer('id_website')->nullable(); 22 | $table->integer('id_media')->nullable(); 23 | $table->tinyInteger('id_author')->nullable(); 24 | $table->tinyInteger('published')->default(0)->nullable(); 25 | $table->date('post_date')->useCurrent(); 26 | $table->string('meta_title')->nullable(); 27 | $table->string('meta_description')->nullable(); 28 | $table->timestamps(); 29 | $table->softDeletes(); 30 | $table->engine = 'InnoDB'; 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | * 37 | * @return void 38 | */ 39 | public function down() 40 | { 41 | Schema::dropIfExists('post'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /database/migrations/2019_01_21_051441_post_category_assign.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('id_post')->default()->nullable(); 19 | $table->string('id_category')->default()->nullable(); 20 | $table->integer('id_lang')->default()->nullable(); 21 | $table->timestamps(); 22 | $table->softDeletes(); 23 | $table->engine = 'InnoDB'; 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('post_category_assign'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2019_01_21_051657_media.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name')->default()->nullable(); 19 | $table->string('path')->default()->nullable(); 20 | $table->string('media_type')->default()->nullable(); 21 | $table->string('type')->default()->nullable(); 22 | $table->string('title')->default()->nullable(); 23 | $table->string('format')->default()->nullable(); 24 | $table->integer('status')->unsigned()->default()->nullable(); 25 | $table->timestamps(); 26 | $table->softDeletes(); 27 | $table->engine = 'InnoDB'; 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | * 34 | * @return void 35 | */ 36 | public function down() 37 | { 38 | Schema::dropIfExists('media'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/2019_01_21_051833_media_image_size.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('id_media')->unsigned()->default()->nullable(); 19 | $table->string('size')->nullable(); 20 | $table->smallInteger('webp')->default(0)->nullable(); 21 | $table->timestamps(); 22 | $table->softDeletes(); 23 | $table->engine = 'InnoDB'; 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('media_image_size'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/seeds/PostSeeder.php: -------------------------------------------------------------------------------- 1 | create() 24 | ->each(function ($post) { 25 | $post->post_category()->save(factory(App\Objects\PostCategory::class)->make()); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /middleware/AdminUser.php: -------------------------------------------------------------------------------- 1 | user()) { 14 | 15 | $admin_route = config('adlara.admin_route') . '/app'; 16 | 17 | if (!request()->ajax()) { 18 | 19 | return redirect($admin_route . '/login'); 20 | 21 | } 22 | 23 | $data = array( 24 | 'status' => 'redirect', 25 | 'message' => url($admin_route . '/login') 26 | ); 27 | 28 | echo json_encode($data); 29 | exit(); 30 | 31 | } 32 | 33 | return $next($request); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /middleware/VerifyCSRFToken.php: -------------------------------------------------------------------------------- 1 | hasMany('App\Objects\Post', 'id_author'); 36 | } 37 | 38 | public function getAdminUser($id = null) 39 | { 40 | if ($id) { 41 | return $this->find($id); 42 | } 43 | 44 | if (Auth::guard('admin')->check()) { 45 | return Auth::guard('admin')->user(); 46 | } 47 | 48 | return $this; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /objects/IDB.php: -------------------------------------------------------------------------------- 1 | status = (int) $status; 13 | $this->save(); 14 | } 15 | 16 | public function updateColumn($column, $val) 17 | { 18 | $this->$column = (int) $val; 19 | $this->save(); 20 | } 21 | 22 | public function getSql() 23 | { 24 | $builder = $this->getBuilder(); 25 | $sql = $builder->toSql(); 26 | foreach($builder->getBindings() as $binding) 27 | { 28 | $value = is_numeric($binding) ? $binding : "'".$binding."'"; 29 | $sql = preg_replace('/\?/', $value, $sql, 1); 30 | } 31 | return $sql; 32 | } 33 | 34 | public function check($key, $val) 35 | { 36 | $data = $this->where($key, $val); 37 | if (isset($data->id) && $data->id) { 38 | return true; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | public function findByURL($url) 45 | { 46 | $this->primaryKey = 'url'; 47 | return $this->find($url); 48 | } 49 | 50 | public function joinMediaURL($size1 = null, $size2 = null, $webp = true) 51 | { 52 | $obj = $this; 53 | $obj->url = $this->retrieve($size1, $size2, $webp); 54 | return $obj; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /objects/Media.php: -------------------------------------------------------------------------------- 1 | disk = config('filesystems.default'); 31 | } 32 | 33 | public function saveImageSize() 34 | { 35 | if (!$this->id) { 36 | return; 37 | } 38 | 39 | $mis = new MediaImageSize; 40 | $size_folder = trim($this->size1) . trim($this->size2); 41 | 42 | $size_db = $mis->where('id_media', $this->id) 43 | ->where('size', $size_folder) 44 | ->first(); 45 | 46 | if ($size_db) { 47 | return; 48 | } 49 | 50 | $mis->id_media = $this->id; 51 | $mis->size = $size_folder; 52 | $mis->save(); 53 | } 54 | 55 | public function saveWebpImageSize() 56 | { 57 | if (!$this->id) { 58 | return; 59 | } 60 | 61 | $mis = new MediaImageSize; 62 | $size_folder = trim($this->size1) . trim($this->size2); 63 | 64 | $size_db = $mis->where('id_media', $this->id) 65 | ->where('size', $size_folder) 66 | ->where('webp', 1) 67 | ->first(); 68 | 69 | if ($size_db) { 70 | return; 71 | } 72 | 73 | $mis->id_media = $this->id; 74 | $mis->size = $size_folder; 75 | $mis->webp = 1; 76 | $mis->save(); 77 | } 78 | 79 | public function getOriginalImageURL() 80 | { 81 | if (!$this->path) { 82 | //Log here 83 | } 84 | 85 | $disk = $this->disk; 86 | $storage = Storage::disk($disk); 87 | 88 | if (!$this->webp_path) { 89 | $this->generateWebpImage(); 90 | } 91 | 92 | return [ 93 | 'webp' => $storage->url($this->webp_path), 94 | 'jpg' => $storage->url($this->path) 95 | ]; 96 | } 97 | 98 | public function getStorageFolder($webp = false) 99 | { 100 | $type = $this->type; 101 | $folder = ''; 102 | 103 | // if (config('filesystems.cloud') == 'local') { 104 | // $folder .= 'app/'; 105 | // } 106 | 107 | if (!$webp) { 108 | 109 | $folder = 'public/image/jpg'; 110 | 111 | } else { 112 | 113 | $folder = 'public/image/webp'; 114 | 115 | } 116 | 117 | if ($this->size1 && $this->size2) { 118 | $folder .= '/' . trim($this->size1) . trim($this->size2); 119 | } 120 | 121 | return $folder . '/'; 122 | } 123 | 124 | // This function is temporary to move files f 125 | public function getOldStorageFolder() 126 | { 127 | $type = $this->type; 128 | $folder = ''; 129 | 130 | // if (config('filesystems.cloud') == 'local') { 131 | // $folder .= 'app/'; 132 | // } 133 | 134 | $folder = 'public/image'; 135 | 136 | if ($this->size1 && $this->size2) { 137 | $folder .= '/' . trim($this->size1) . trim($this->size2); 138 | } 139 | 140 | return $folder . '/'; 141 | } 142 | 143 | public function makeWebpImage($image_path = null, $max_size) 144 | { 145 | $pathinfo = pathinfo($this->path); 146 | $ext = $pathinfo['extension']; 147 | $filename = $pathinfo['filename']; 148 | $new_name = $filename . '.webp'; 149 | 150 | if ($ext == 'webp') { 151 | return; 152 | } 153 | 154 | $this->moveImageToLocalStorage(); 155 | 156 | $storage = Storage::disk('local'); 157 | 158 | $localPath = storage_path('app/public/image/' . $new_name); 159 | $bytes = $storage->size($this->path); 160 | 161 | $image_path = $storage->path($this->path); 162 | 163 | if ($bytes) { 164 | 165 | $size_in_kb = ceil($bytes/1000); 166 | 167 | if ($size_in_kb > $max_size) { 168 | 169 | //Optimizing image for its size and replacing at its destination 170 | $this->optimizeImage($image_path, false); 171 | 172 | } 173 | 174 | } 175 | 176 | $image_type = image_type_to_mime_type(exif_imagetype($image_path)); 177 | 178 | if ($image_type == 'image/png') { 179 | $img1 = imagecreatefrompng($image_path); 180 | } 181 | 182 | if ($image_type == 'image/jpg' || $image_type == 'image/jpeg') { 183 | $img1 = imagecreatefromjpeg($image_path); 184 | imagepalettetotruecolor($img1); 185 | } 186 | 187 | if ($image_type == 'image/gif') { 188 | $img1 = imagecreatefromgif($image_path); 189 | } 190 | 191 | if ( 192 | $image_type == 'image/png' || 193 | $image_type == 'image/jpeg' || 194 | $image_type == 'image/jpg' || 195 | $image_type == 'image/gif' 196 | ) { 197 | imagepalettetotruecolor($img1); 198 | $create = imagewebp($img1, $localPath, 100); 199 | imagedestroy($img1); 200 | 201 | $nameinfo = pathinfo($this->name); 202 | $new_real_name = $pathinfo['filename'] . '.webp'; 203 | 204 | $this->name = $new_real_name; 205 | $this->realname = $new_real_name; 206 | $this->path = 'image/' . $new_name; 207 | $this->format = 'webp'; 208 | $this->save(); 209 | $this->localStorageToS3Storage(); 210 | } 211 | 212 | } 213 | 214 | public function retrieve($size1 = null, $size2 = null, $webp = false) 215 | { 216 | if ($this->type == 'image') { 217 | if (!$size1 || !$size2) { 218 | return $this->getOriginalImageURL(); 219 | } 220 | 221 | return $this->resizeImage($size1, $size2, $webp); 222 | } 223 | 224 | if ($this->format == 'embeded') { 225 | return $this->name; 226 | } 227 | 228 | $disk = $this->disk; 229 | $url = Storage::disk($disk)->url($this->path); 230 | return $url; 231 | } 232 | 233 | public function getSizeFolder() 234 | { 235 | if (!$this->size1 || !$this->size2) { 236 | return; 237 | } 238 | 239 | return $this->size1 . $this->size2; 240 | } 241 | 242 | /* 243 | | 244 | | Variable $filePath is the key variable which will be used to define the path 245 | | 246 | */ 247 | 248 | public function resizeImage($size1, $size2, $webp = false) 249 | { 250 | $this->size1 = $size1; 251 | $this->size2 = $size2; 252 | 253 | //Cleaning name 254 | $this->cleanName($this->name); 255 | 256 | if ($webp) { 257 | 258 | return [ 259 | 'jpg' => $this->resizeOtherImage(), 260 | 'webp' => $this->resizeWebpImage() 261 | ]; 262 | 263 | } else { 264 | 265 | return $this->resizeOtherImage(); 266 | 267 | } 268 | } 269 | 270 | protected function getFileNameWithoutExtension($file) 271 | { 272 | $name = pathinfo($file); 273 | return $name['filename']; 274 | } 275 | 276 | protected function getFileExtension($file) 277 | { 278 | $name = pathinfo($file); 279 | return $name['extension']; 280 | } 281 | 282 | 283 | protected function resizeWebpImage() 284 | { 285 | $disk = $this->disk; 286 | $storage = Storage::disk($disk); 287 | 288 | $resizeNotRequireFormats = [ 289 | 'svg+xml', 290 | 'svg', 291 | 'xml' 292 | ]; 293 | 294 | // If unsupported format is there, then it should not resize 295 | if (in_array($this->format, $resizeNotRequireFormats)) { 296 | 297 | return $storage->url($this->path); 298 | 299 | } 300 | 301 | $folder = $this->getStorageFolder(true); 302 | 303 | //File path means folder + original path (i.e. 250250/filename.jpg) & $this->path is the real path 304 | $filePath = $folder . $this->getFileNameWithoutExtension($this->name) . '.webp'; 305 | 306 | // If file exists then return it 307 | if ($this->sizeTableHasTheWebpImage()) { 308 | // if ($storage->exists($filePath)) { 309 | 310 | // $this->moveImage($filePath); 311 | 312 | $url = $storage->url($filePath); 313 | 314 | return $url; 315 | 316 | } 317 | 318 | if (!$this->webp_path) { 319 | $this->generateWebpImage(); 320 | } 321 | 322 | //Image content used to resize image through intervention 323 | $storedImage = $storage->get($this->webp_path); 324 | 325 | if (!$storedImage) { 326 | 327 | $mesage = 'Content missing for Image (Webp) ID - ' . $this->id; 328 | 329 | triggerException($message, E_USER_WARNING); 330 | 331 | return ''; 332 | } 333 | 334 | // Since we have to resize from the webp_format, we have to move file to the local storage to create binary data from the given path 335 | 336 | // Moving image to local storage 337 | $this->moveWebpImageToLocalStorage(); 338 | 339 | // getting path of the moved image 340 | $local_path = Storage::disk('local')->path($this->webp_path); 341 | 342 | // Binary data of webp image 343 | $storedImage = imagecreatefromwebp($local_path); 344 | 345 | // Since the image processing is done, we should delete it to clear space 346 | Storage::disk('local')->delete($this->webp_path); 347 | 348 | //Making it ready for resizing with Intervention 349 | $img = Image::make($storedImage); 350 | $img->resize($this->size1, $this->size2, function ($constraint) { 351 | $constraint->aspectRatio(); 352 | }); 353 | 354 | // We need a path where resized image can be stored 355 | if ($this->disk == 's3') { 356 | 357 | $file = storage_path('app/tmp/webp/' . $this->getFileNameWithoutExtension($this->name) . '.webp'); //tmp path 358 | 359 | } else { 360 | 361 | $localStorage = Storage::disk('local'); 362 | $localPath = $localStorage->path(''); 363 | $localFolder = $localPath . $folder; 364 | 365 | if (!file_exists($localFolder)) { 366 | 367 | $localStorage->makeDirectory($folder); 368 | 369 | } 370 | 371 | $file = storage_path('app/' . $filePath); 372 | 373 | } 374 | 375 | //Finally saving a file 376 | $img->save($file); 377 | 378 | //Now move local file to s3 bucket 379 | if ($this->disk == 's3') { 380 | 381 | $fetchTmpFile = Storage::disk('local')->get('tmp/webp/' . $this->getFileNameWithoutExtension($this->name) . '.webp'); 382 | 383 | //Moving local file to s3 bucket after resizing 384 | $storage->put($filePath, $fetchTmpFile, 'public'); 385 | 386 | //delete local file 387 | Storage::disk('local')->delete('tmp/webp/' . $this->getFileNameWithoutExtension($this->name) . '.webp'); 388 | 389 | } 390 | 391 | $this->saveWebpImageSize(); 392 | return $storage->url($filePath); 393 | } 394 | 395 | protected function moveImage($newPath) 396 | { 397 | $storage = Storage::disk($this->disk); 398 | $filePath = $this->getOldStorageFolder() . $this->name; 399 | 400 | if ($storage->exists($filePath) && !$storage->exists($newPath)) { 401 | 402 | $storage->move($filePath, $newPath); 403 | 404 | } 405 | 406 | } 407 | 408 | protected function resizeOtherImage() 409 | { 410 | $disk = $this->disk; 411 | $storage = Storage::disk($disk); 412 | 413 | $resizeNotRequireFormats = [ 414 | 'svg+xml', 415 | 'svg', 416 | 'xml' 417 | ]; 418 | 419 | // If unsupported format is there, then it should not resize 420 | if (in_array($this->format, $resizeNotRequireFormats)) { 421 | 422 | return $storage->url($this->path); 423 | 424 | } 425 | 426 | $folder = $this->getStorageFolder(); 427 | 428 | //File path means folder + original path (i.e. 250250/filename.jpg) & $this->path is the real path 429 | $filePath = $folder . $this->name; 430 | 431 | // If file exists then return it 432 | if ($this->sizeTableHasTheImage()) { 433 | 434 | // if ($storage->exists($filePath)) { 435 | 436 | // $this->moveImage($filePath); 437 | 438 | $url = $storage->url($filePath); 439 | return $url; 440 | 441 | } 442 | 443 | //Image content used to resize image through intervention 444 | if ($storage->exists($this->path)) { 445 | 446 | $mime = $storage->mimeType($this->path); 447 | 448 | if (!in_array($mime, [ 449 | 'image/jpeg', 450 | 'image/png', 451 | 'image/bmp', 452 | 'image/gd2', 453 | 'image/xbm', 454 | 'image/xpm', 455 | 'image/webp' 456 | ])) { 457 | 458 | return notFoundImage(); 459 | 460 | } 461 | 462 | $storedImage = $storage->get($this->path); 463 | 464 | } else { 465 | 466 | $message = 'Content missing for Image ID - ' . $this->id; 467 | 468 | // triggerException($message, E_USER_WARNING); 469 | 470 | return notFoundImage(); 471 | 472 | } 473 | 474 | //Making it ready for resizing with Intervention 475 | $img = Image::make($storedImage); 476 | $img->resize($this->size1, $this->size2, function ($constraint) { 477 | $constraint->aspectRatio(); 478 | }); 479 | 480 | // We need a path where resized image can be stored 481 | if ($this->disk == 's3') { 482 | 483 | $file = storage_path('app/tmp/' . $this->name); //tmp path 484 | 485 | } else { 486 | 487 | $localStorage = Storage::disk('local'); 488 | $localPath = $localStorage->path(''); 489 | $localFolder = $localPath . $folder; 490 | 491 | if (!file_exists($localFolder)) { 492 | 493 | $localStorage->makeDirectory($folder); 494 | 495 | } 496 | 497 | $file = storage_path('app/' . $filePath); 498 | 499 | } 500 | 501 | //Finally saving a file 502 | $img->save($file); 503 | 504 | //Now move local file to s3 bucket 505 | if ($this->disk == 's3') { 506 | 507 | $fetchTmpFile = Storage::disk('local')->get('tmp/' . $this->name); 508 | 509 | //Moving local file to s3 bucket after resizing 510 | $storage->put($filePath, $fetchTmpFile, 'public'); 511 | 512 | //delete local file 513 | Storage::disk('local')->delete('tmp/' . $this->name); 514 | 515 | } 516 | 517 | $this->saveImageSize(); 518 | return $storage->url($filePath); 519 | } 520 | 521 | public function moveImageToLocalStorage() 522 | { 523 | //Check if file exists locally 524 | $exists = Storage::disk('local')->exists($this->path); 525 | 526 | if (!$exists) { 527 | 528 | if (!Storage::disk('s3')->exists($this->path)) { 529 | pre($this); 530 | } 531 | 532 | //Fetch content from the s3 bucket 533 | $cloud_file = Storage::disk('s3')->get($this->path); 534 | 535 | //storing the file locally 536 | $test = Storage::disk('local')->put($this->path, $cloud_file, 'public'); 537 | } 538 | } 539 | 540 | protected function moveWebpImageToLocalStorage() 541 | { 542 | //Check if file exists locally 543 | $exists = Storage::disk('local')->exists($this->webp_path); 544 | 545 | if (!$exists) { 546 | //Fetch content from the s3 bucket 547 | $cloud_file = Storage::disk('s3')->get($this->webp_path); 548 | 549 | //storing the file locally 550 | $test = Storage::disk('local')->put($this->webp_path, $cloud_file, 'public'); 551 | } 552 | } 553 | 554 | public function compress($source, $destination, $quality = 90) 555 | { 556 | $info = getimagesize($source); 557 | 558 | if ($info['mime'] == 'image/jpeg') { 559 | $image = imagecreatefromjpeg($source); 560 | } 561 | 562 | elseif ($info['mime'] == 'image/gif') { 563 | $image = imagecreatefromgif($source); 564 | } 565 | 566 | elseif ($info['mime'] == 'image/png') { 567 | $image = imagecreatefrompng($source); 568 | } 569 | 570 | imagejpeg($image, $destination, $quality); 571 | imagedestroy($image); 572 | 573 | return $destination; 574 | } 575 | 576 | public function optimizeImage($src_path = null, $sync_image = false) 577 | { 578 | if (!$this->id) { 579 | return; 580 | } 581 | 582 | if ($this->disk == 's3' && $sync_image) { 583 | $this->moveImageToLocalStorage(); 584 | } 585 | 586 | if (!$src_path) { 587 | 588 | $src = $src_path; 589 | $dest = $src_path; 590 | 591 | } else { 592 | 593 | $src = storage_path('app/' . $this->path); 594 | $dest = storage_path('app/' . $this->path); 595 | 596 | } 597 | 598 | 599 | $this->compress($src, $dest, 90); 600 | 601 | $this->localStorageToS3Storage(); 602 | 603 | \Log::info('Image optimized - ' . $this->id); 604 | } 605 | 606 | public function localStorageToS3Storage($delete = true) 607 | { 608 | //Fetching local file 609 | $locallyStoredFile = Storage::disk('local')->get($this->path); 610 | 611 | //Putting local file into s3 bucket 612 | Storage::disk('s3')->put($this->path, $locallyStoredFile, 'public'); 613 | 614 | if ($delete) { 615 | //Deleting local file 616 | Storage::disk('local')->delete($this->path); 617 | } 618 | 619 | return Storage::disk('s3')->url($this->path); 620 | } 621 | 622 | public function moveLocalWebpImagetoS3Storage($delete = true) 623 | { 624 | if (!$this->webp_path) { 625 | return; 626 | } 627 | 628 | //Fetching local file 629 | $locallyStoredFile = Storage::disk('local')->get($this->webp_path); 630 | 631 | //Putting local file into s3 bucket 632 | $putted = Storage::disk('s3')->put($this->webp_path, $locallyStoredFile, 'public'); 633 | 634 | if ($delete) { 635 | //Deleting local file 636 | Storage::disk('local')->delete($this->webp_path); 637 | } 638 | } 639 | 640 | public function sizeTableHasTheImage() 641 | { 642 | if ( 643 | !$this->size1 || 644 | !$this->size2 || 645 | !$this->id || 646 | $this->force_resize 647 | ) { 648 | return false; //Log 649 | } 650 | 651 | $size = $this->size1 . $this->size2; 652 | return \App\Objects\MediaImageSize::where('size', $size) 653 | ->where('id_media', $this->id) 654 | ->first(); 655 | } 656 | 657 | public function sizeTableHasTheWebpImage() 658 | { 659 | if ( 660 | !$this->size1 || 661 | !$this->size2 || 662 | !$this->id || 663 | $this->force_webp_resize 664 | ) { 665 | return false; //Log 666 | } 667 | 668 | $size = $this->size1 . $this->size2; 669 | 670 | return \App\Objects\MediaImageSize::where('size', $size) 671 | ->where('webp', 1) 672 | ->where('id_media', $this->id) 673 | ->first(); 674 | } 675 | 676 | private function storeMedia($file, $folder, $disk, $type) 677 | { 678 | if ($type == 'image') { 679 | 680 | $size = ceil($file->getSize()/1000); 681 | 682 | if ($size >= 200) { 683 | 684 | $tmpStoredFilePath = $file->store($folder, 'local'); 685 | 686 | $source = Storage::disk('local')->path($tmpStoredFilePath); 687 | $destination = $source; 688 | 689 | $this->compress($source, $destination); 690 | 691 | if (config('filesystems.default') == 's3') { 692 | 693 | $tmp_file = new File(Storage::disk('local')->path($tmpStoredFilePath)); 694 | 695 | $path = Storage::disk('s3')->putFile($folder, $tmp_file, 'public'); 696 | 697 | Storage::disk('local')->delete($tmpStoredFilePath); 698 | 699 | } else { 700 | 701 | $path = $tmpStoredFilePath; 702 | 703 | } 704 | 705 | return $path; 706 | } 707 | 708 | } 709 | 710 | return $file->storePublicly($folder, $disk); 711 | } 712 | 713 | public function store($file) 714 | { 715 | $disk = $this->disk; 716 | $name = $file->getClientOriginalName(); 717 | $format = $file->getClientMimeType(); 718 | $type = explode('/', $format)[0]; 719 | 720 | if ($type == 'image' && $format != 'image/webp') { 721 | 722 | $folder = 'public/' . $type . '/jpg'; 723 | 724 | } else { 725 | 726 | $folder = 'public/' . $format; 727 | 728 | } 729 | 730 | //Storing file 731 | $storedFilePath = $this->storeMedia( 732 | $file, 733 | $folder, 734 | $disk, 735 | $type 736 | ); 737 | 738 | $error = $file->getError(); 739 | 740 | if ($error) { 741 | return array( 742 | 'status' => 'error', 743 | 'message' => $error 744 | ); 745 | } 746 | 747 | if (!$storedFilePath) { 748 | return array( 749 | 'status' => 'error', 750 | 'message' => 'File ' . $name . ' could not be uploaded' 751 | ); 752 | } 753 | 754 | $url = Storage::disk($disk)->url($storedFilePath); 755 | 756 | $this->name = $name; 757 | $this->path = $storedFilePath; 758 | 759 | if ($format == 'image/webp') { 760 | 761 | $this->webp_path = $storedFilePath; 762 | 763 | } 764 | 765 | $this->type = $type; 766 | $this->format = $format; 767 | $this->save(); 768 | $this->name = $this->id . '-' . $this->name; 769 | $this->save(); 770 | 771 | if ($type == 'image') { 772 | 773 | $this->imageMirroring(); 774 | $this->generateCommonSizes(); 775 | 776 | } 777 | 778 | return array( 779 | 'url' => $url, 780 | 'id' => $this->id 781 | ); 782 | } 783 | 784 | private function generateCommonSizes() 785 | { 786 | $this->retrieve(250, 250); 787 | } 788 | 789 | private function imageMirroring() 790 | { 791 | if (config('filesystems.default') != 's3') { 792 | return; 793 | } 794 | 795 | if ($this->format == 'webp' || $this->format == 'image/webp') { 796 | 797 | $this->generateJpgImage(); 798 | 799 | } else { 800 | 801 | $this->generateWebpImage(); 802 | 803 | } 804 | } 805 | 806 | private function storage() 807 | { 808 | return Storage::disk($this->disk); 809 | } 810 | 811 | public function cleanName($name) 812 | { 813 | $pathinfo = pathinfo($name); 814 | $ext = $pathinfo['extension']; 815 | $filename = preg_replace('/[^\w\-]/', '', $pathinfo['filename']); 816 | $new_name = $filename . '.' . $ext; 817 | 818 | if ($new_name != $name) { 819 | $this->name = $new_name; 820 | $this->save(); 821 | 822 | //Delete sizes 823 | $mis = MediaImageSize::where('id_media', $this->id) 824 | ->delete(); 825 | } 826 | } 827 | 828 | public function adjustPathForWebp() 829 | { 830 | $this->moveImageToLocalStorage(); 831 | 832 | $image = storage_path('app/' . $this->path); 833 | 834 | $pathinfo = pathinfo($this->path); 835 | $ext = $pathinfo['extension']; 836 | $filename = $pathinfo['filename']; 837 | 838 | $local_jpg_path = storage_path('app/public/image/jpg/' . $filename . '.jpg'); 839 | $local_webp_path = storage_path('app/public/image/webp/' . $filename . '.webp'); 840 | 841 | $format = image_type_to_mime_type(exif_imagetype($image)); 842 | 843 | $type_ex = explode('/' , $format); 844 | 845 | $type_of_image = end($type_ex); 846 | 847 | if ($format == 'image/webp') { 848 | 849 | $image = imagecreatefromwebp($image); 850 | imagejpeg($image, $local_jpg_path, 100); 851 | imagedestroy($image); 852 | $this->path = 'image/jpg/' . $filename . '.jpg'; 853 | $this->save(); 854 | $this->webp_path = 'image/webp/' . $filename . '.webp'; 855 | 856 | } else { 857 | 858 | if (!in_array($type_of_image, [ 859 | 'jpeg', 860 | 'png', 861 | 'bmp', 862 | 'gd2', 863 | 'xbm', 864 | 'xpm' 865 | ])) { 866 | 867 | return; 868 | 869 | } 870 | 871 | $fun = 'imagecreatefrom' . $type_of_image; 872 | $image = $fun($image); 873 | imagewebp($image, $local_webp_path, 100); 874 | 875 | $this->webp_path = 'image/webp/' . $filename . '.webp'; 876 | $this->save(); 877 | pre($this->id, false); 878 | $this->moveLocalWebpImagetoS3Storage(); 879 | 880 | } 881 | 882 | $this->localStorageToS3Storage(); 883 | } 884 | 885 | /* 886 | | 887 | | This function was created to remove webp extension from the name column which was added | previously by mistake 888 | | 889 | */ 890 | public function adjustExtension() 891 | { 892 | $filename = $this->getFileNameWithoutExtension($this->name); 893 | $finalName = $filename . '.jpg'; 894 | $this->name = $finalName; 895 | $this->format = 'jpg'; 896 | $this->save(); 897 | pre($this->id, false); 898 | } 899 | 900 | protected function generateWebpImage() 901 | { 902 | //Moving image to local storage 903 | $this->moveImageToLocalStorage(); 904 | 905 | // Local storage path 906 | $image = Storage::disk('local')->path($this->path); 907 | 908 | // Fetching Format from the above path 909 | $format = image_type_to_mime_type(exif_imagetype($image)); 910 | 911 | // Exploding the format 912 | $type_ex = explode('/' , $format); 913 | 914 | // Taking the last key from the array to determin the image type 915 | $type_of_image = end($type_ex); 916 | 917 | // getting file name without extension to save image with extension webp 918 | $filename = $this->getFileNameWithoutExtension($this->name); 919 | $local_webp_path = storage_path('app/public/image/webp/' . $filename . '.webp'); 920 | 921 | if (!in_array($type_of_image, [ 922 | 'jpeg', 923 | 'png', 924 | 'bmp', 925 | 'gd2', 926 | 'xbm', 927 | 'xpm' 928 | ])) { 929 | 930 | return; 931 | 932 | } 933 | 934 | // As per the image type coverting it into the webp image without loosing quality 935 | $fun = 'imagecreatefrom' . $type_of_image; 936 | $image = $fun($image); 937 | imagepalettetotruecolor($image); 938 | imagewebp($image, $local_webp_path, 95); 939 | imagedestroy($image); 940 | 941 | // Saving webp path 942 | $this->webp_path = 'image/webp/' . $filename . '.webp'; 943 | $this->save(); 944 | 945 | // Finally moving file to the s3 storage 946 | $this->moveLocalWebpImagetoS3Storage(); 947 | } 948 | 949 | protected function generateJpgImage() 950 | { 951 | //Moving image to local storage 952 | $this->moveImageToLocalStorage(); 953 | 954 | // Local storage path 955 | $image = Storage::disk('local')->path($this->path); 956 | 957 | // getting file name without extension to save image with extension webp 958 | $filename = $this->getFileNameWithoutExtension($this->name) . '.jpg'; 959 | $local_jpg_path = storage_path('app/public/image/jpg/' . $filename); 960 | // As per the image type coverting it into the webp image without loosing quality 961 | $image = imagecreatefromwebp($image); 962 | imagepalettetotruecolor($image); 963 | imagejpeg($image, $local_jpg_path, 100); 964 | imagedestroy($image); 965 | 966 | // Saving webp path 967 | $this->path = 'image/jpg/' . $filename; 968 | $this->save(); 969 | 970 | // Finally moving file to the s3 storage 971 | $this->localStorageToS3Storage(); 972 | } 973 | 974 | public function remove($with_sizes = true) 975 | { 976 | $storage = Storage::disk($this->disk); 977 | 978 | if ($with_sizes && $this->type == 'image') { 979 | 980 | $sizes = MediaImageSize::where('id_media', $this->id) 981 | ->get(); 982 | 983 | foreach ($sizes as $size) { 984 | 985 | $path1 = 'image/jpg/' . $size->size . '/' . $this->name; 986 | 987 | if ($storage->exists($path1)) { 988 | // $storage->delete($path1); 989 | } 990 | 991 | if ($size->webp) { 992 | 993 | $path2 = 'image/webp/' . $size->size . '/' . $this->getFileNameWithoutExtension($this->name) . '.webp'; 994 | 995 | if ($storage->exists($path2)) { 996 | $storage->delete($path2); 997 | } 998 | 999 | } 1000 | 1001 | // Delete from the table 1002 | $size->delete(); 1003 | 1004 | } 1005 | 1006 | // Forcing the object to be deleted from the table 1007 | $this->forceDelete(); 1008 | 1009 | } 1010 | } 1011 | 1012 | public function githubTest() 1013 | { 1014 | return 'test'; 1015 | } 1016 | 1017 | public function fixNaming() 1018 | { 1019 | $this->moveImageToLocalStorage(); 1020 | 1021 | $filename = \Str::slug($this->getFileNameWithoutExtension($this->name)); 1022 | $ext = $this->getFileExtension($this->name); 1023 | 1024 | $new_name = $filename . '.' . $ext; 1025 | 1026 | $path_e = explode('/', $this->path); 1027 | $last_key = array_key_last($path_e); 1028 | if (isset($path_e[$last_key])) { 1029 | 1030 | $path_e[$last_key] = $new_name; 1031 | $new_path = implode('/', $path_e); 1032 | 1033 | //Renaming to new path 1034 | Storage::disk('local')->move($this->path, $new_path); 1035 | 1036 | $this->name = $new_name; 1037 | $this->path = $new_path; 1038 | $this->save(); 1039 | 1040 | $this->localStorageToS3Storage(); 1041 | } 1042 | } 1043 | 1044 | public function fixWebpNaming() 1045 | { 1046 | if (!$this->webp_path) { 1047 | return; 1048 | } 1049 | 1050 | $this->moveWebpImageToLocalStorage(); 1051 | 1052 | $filename = \Str::slug($this->getFileNameWithoutExtension($this->name)); 1053 | $ext = $this->getFileExtension($this->name); 1054 | 1055 | $new_name = $filename . '.' . $ext; 1056 | 1057 | $path_e = explode('/', $this->webp_path); 1058 | $last_key = array_key_last($path_e); 1059 | 1060 | if (isset($path_e[$last_key])) { 1061 | 1062 | $path_e[$last_key] = $new_name; 1063 | $new_path = implode('/', $path_e); 1064 | 1065 | //Renaming to new path 1066 | // Storage::disk('local')->move($this->webp_path, $new_path); 1067 | 1068 | $this->name = $new_name; 1069 | $this->webp_path = $new_path; 1070 | $this->save(); 1071 | 1072 | $this->localStorageToS3Storage(); 1073 | 1074 | pre(Storage::disk('s3')->url($this->webp_path)); 1075 | } 1076 | } 1077 | } 1078 | -------------------------------------------------------------------------------- /objects/MediaImageSize.php: -------------------------------------------------------------------------------- 1 | belongsTo('App\Objects\Media', 'id_media'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /objects/Page.php: -------------------------------------------------------------------------------- 1 | belongsToMany('App\Objects\PostCategory', 'post_category_assign', 'id_post', 'id_category'); 15 | } 16 | 17 | public function image() 18 | { 19 | return $this->belongsTo('App\Objects\Media', 'id_media'); 20 | } 21 | 22 | public function author() 23 | { 24 | return $this->belongsTo('App\Objects\AdminUser', 'id_author'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /objects/PostCategory.php: -------------------------------------------------------------------------------- 1 | belongsToMany('App\Objects\Post', 'post_category_assigned', 'id_category', 'id_post'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /objects/PostCategoryAssigned.php: -------------------------------------------------------------------------------- 1 | belongsTo('App\Objects\Post', 'id_post'); 16 | } 17 | 18 | public function category() 19 | { 20 | return $this->belongsTo('App\Objects\PostCategory', 'id_category'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "prod": "npm run production", 8 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "watch": "npm run development -- --watch", 10 | "watch-poll": "npm run watch -- --watch-poll" 11 | }, 12 | "dependencies": { 13 | "@mdi/font": "^4.4.95", 14 | "@uppy/core": "^1.4.0", 15 | "@uppy/dashboard": "^1.3.0", 16 | "@uppy/xhr-upload": "^1.3.0", 17 | "babel-runtime": "^6.26.0", 18 | "debounce": "^1.2.0", 19 | "jquery": "^3.5.0", 20 | "module": "^1.2.5", 21 | "summernote": "^0.8.16", 22 | "vue-server-renderer": "^2.6.10", 23 | "vuetify": "^2.0.0", 24 | "vuetify-google-autocomplete": "^2.0.0-beta.6" 25 | }, 26 | "devDependencies": { 27 | "fs": "0.0.1-security", 28 | "axios": ">=0.21.1", 29 | "cross-env": "^5.1", 30 | "laravel-mix": "^4.0.7", 31 | "resolve-url-loader": "^2.3.1", 32 | "sass": "^1.17.4", 33 | "sass-loader": "^7.1.0", 34 | "vue": "^2.6.10", 35 | "vue-cli-plugin-vuetify": "^0.6.3", 36 | "vue-router": "^3.1.3", 37 | "vue-template-compiler": "^2.6.10", 38 | "vuetify-loader": "^1.2.2", 39 | "vuex": "^3.1.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 48 | 49 | $this->mapWebRoutes(); 50 | 51 | // 52 | } 53 | 54 | /** 55 | * Define the "web" routes for the application. 56 | * 57 | * These routes all receive session state, CSRF protection, etc. 58 | * 59 | * @return void 60 | */ 61 | protected function mapWebRoutes() 62 | { 63 | $this->mapRoutes(); 64 | } 65 | 66 | /** 67 | * Define the "api" routes for the application. 68 | * 69 | * These routes are typically stateless. 70 | * 71 | * @return void 72 | */ 73 | protected function mapApiRoutes() 74 | { 75 | Route::prefix('api') 76 | ->middleware('api') 77 | ->namespace($this->namespace) 78 | ->group(base_path('routes/api.php')); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /providers/kernel.php: -------------------------------------------------------------------------------- 1 | [ 33 | \App\Http\Middleware\EncryptCookies::class, 34 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 35 | \Illuminate\Session\Middleware\StartSession::class, 36 | // \Illuminate\Session\Middleware\AuthenticateSession::class, 37 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 38 | \App\Http\Middleware\VerifyCsrfToken::class, 39 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 40 | ], 41 | 42 | 'api' => [ 43 | 'throttle:api', 44 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 45 | ], 46 | ]; 47 | 48 | /** 49 | * The application's route middleware. 50 | * 51 | * These middleware may be assigned to groups or used individually. 52 | * 53 | * @var array 54 | */ 55 | protected $routeMiddleware = [ 56 | 'auth' => \App\Http\Middleware\Authenticate::class, 57 | 'admin_user' => \App\Http\Middleware\AdminUser::class, 58 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 59 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 60 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 61 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 62 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 63 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 64 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 65 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 66 | ]; 67 | } 68 | -------------------------------------------------------------------------------- /routes/admin.php: -------------------------------------------------------------------------------- 1 | 'api', 'middleware' => 'admin_user'], function () { 21 | 22 | Route::get('post/category/add', 'PostCategoryController@initContentCreate')->name('post_category.add'); 23 | Route::post('post/category/add', 'PostCategoryController@initProcessCreate'); 24 | Route::get('post/category/edit/{id}', 'PostCategoryController@initContentCreate')->name('post_category.edit'); 25 | Route::post('post/category/edit/{id}', 'PostCategoryController@initProcessCreate'); 26 | Route::get('post/category', 'PostCategoryController@initListing')->name('post_category.list'); 27 | Route::get('post/category/delete/{id}', 'PostCategoryController@initProcessDelete')->name('post_category.delete'); 28 | 29 | Route::get('post/add', 'PostController@initContentCreate')->name('post.add'); 30 | Route::post('post/add', 'PostController@initProcessCreate'); 31 | Route::get('post/edit/{id}', 'PostController@initContentCreate')->name('post.edit'); 32 | Route::post('post/edit/{id}', 'PostController@initProcessCreate'); 33 | Route::get('post', 'PostController@initListing')->name('post.list'); 34 | Route::get('post/delete/{id}', 'PostController@initProcessDelete')->name('post.delete'); 35 | 36 | Route::get('page/add', 'PageController@initContentCreate')->name('page.add'); 37 | Route::post('page/add', 'PageController@initProcessCreate'); 38 | Route::get('page/edit/{id}', 'PageController@initContentCreate')->name('page.edit'); 39 | Route::post('page/edit/{id}', 'PageController@initProcessCreate'); 40 | Route::get('page', 'PageController@initListing')->name('page.list'); 41 | 42 | Route::post('change/status', 'PageController@initProcessChangeStatus'); 43 | Route::post('{component}/delete/{id}', 'PageController@initProcessDelete'); 44 | 45 | Route::get('media', 'MediaController@initProcessListing'); 46 | Route::post('media/upload', 'MediaController@initProcessUpload'); 47 | 48 | Route::get('logout', function () { 49 | 50 | \Auth::guard('admin_user')->logout(); 51 | 52 | return redirect('/' . config('adlara.admin_route') . '/app/login'); 53 | 54 | }); 55 | }); -------------------------------------------------------------------------------- /src/Bootable.php: -------------------------------------------------------------------------------- 1 | segments(); 14 | $adminRoute = config('adlara.admin_route'); 15 | 16 | if (isset($urlSegements[0]) && ($urlSegements[0] == $adminRoute)) { 17 | 18 | $this->app->app_scope = 'admin'; 19 | config(['adlara.app_scope' => 'admin']); 20 | view()->addLocation(resource_path('views/admin')); 21 | 22 | } else { 23 | 24 | $this->app->app_scope = 'front'; 25 | view()->addLocation(resource_path('views/front')); 26 | 27 | } 28 | 29 | } 30 | 31 | public function boot() 32 | { 33 | $this->publishes([ 34 | __DIR__.'/../config/adlara.php' => config_path('adlara.php'), 35 | __DIR__.'/../config/auth.php' => config_path('auth.php'), 36 | __DIR__.'/../routes/admin.php' => base_path('routes/admin.php'), 37 | __DIR__.'/../views/admin/dashboard.blade.php' => base_path('resources/views/admin/dashboard.blade.php'), 38 | __DIR__.'/../views/front/welcome.blade.php' => base_path('resources/views/front/welcome.blade.php'), 39 | __DIR__.'/../database/migrations/' => database_path('/migrations'), 40 | __DIR__.'/../database/seeds/' => database_path('/seeds'), 41 | __DIR__.'/../database/factories/' => database_path('/factories'), 42 | __DIR__.'/../controllers/' => base_path('app/Http/Controllers'), 43 | __DIR__.'/../middleware/AdminUser.php' => base_path('app/Http/Middleware/AdminUser.php'), 44 | __DIR__.'/../middleware/VerifyCSRFToken.php' => base_path('app/Http/Middleware/VerifyCSRFToken.php'), 45 | __DIR__.'/../objects/' => base_path('app/Objects'), 46 | __DIR__.'/../providers/RouteServiceProvider.php' => base_path('app/Providers/RouteServiceProvider.php'), 47 | __DIR__.'/../providers/kernel.php' => base_path('app/Http/Kernel.php'), 48 | __DIR__.'/../_vApp/' => base_path('_vApp'), 49 | __DIR__.'/../package.json' => base_path('package.json'), 50 | __DIR__.'/helper.php' => base_path('app/helper.php'), 51 | __DIR__.'/../webpack.mix.js' => base_path('webpack.mix.js') 52 | ], 'adlarafullsetup'); 53 | } 54 | } -------------------------------------------------------------------------------- /src/RoutesProvider.php: -------------------------------------------------------------------------------- 1 | app_scope == 'admin') { 14 | 15 | $namespace = 'App\Http\Controllers\AdminControllers'; 16 | 17 | Route::middleware('web') 18 | ->prefix(config('adlara.admin_route')) 19 | ->namespace($namespace) 20 | ->group(base_path('routes/admin.php')); 21 | 22 | } else { 23 | 24 | $namespace = 'App\Http\Controllers\FrontControllers'; 25 | 26 | Route::middleware('web') 27 | ->namespace($namespace) 28 | ->group(base_path('routes/web.php')); 29 | 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/helper.php: -------------------------------------------------------------------------------- 1 | '; 6 | print_r($array); 7 | echo ''; 8 | 9 | if ($exit) { 10 | exit(); 11 | } 12 | } 13 | 14 | function removeStyle($content) 15 | { 16 | $output = preg_replace('/(<[^>]+) class=".*?"/i', '$1', $content); 17 | $output = str_ireplace('

 

', '', $output); 18 | $output = str_ireplace('


', '', $output); 19 | $output = str_ireplace('

', '', $output); 20 | $output = preg_replace('/]*>[\s| ]*<\/p>/', '', $output); 21 | 22 | // $output = preg_replace('/style[^>]*/', '', $output); 23 | // $output = preg_replace('/class[^>]*/', '', $output); 24 | $output = preg_replace('/(<[^>]+) style=".*?"/i', '$1', $output); 25 | $output = preg_replace('/(<[^>]+) dir=".*?"/i', '$1', $output); 26 | 27 | return $output; 28 | 29 | } 30 | 31 | function protectedString($content) 32 | { 33 | $h = removeStyle($content); 34 | $h = strip_tags($h, '