├── .editorconfig ├── .gitattributes ├── .gitignore ├── .gitmodules ├── .scrutinizer.yml ├── .styleci.yml ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── app ├── config │ ├── .gitignore │ ├── config.example.ini │ ├── default.ini │ ├── routes-api.ini │ ├── routes-cli.ini │ ├── routes-en.ini │ └── webserver │ │ ├── apache │ │ └── f3-cms.local │ │ ├── nginx │ │ ├── f3-cms-ssl.local │ │ └── f3-cms.local │ │ └── ssl │ │ ├── f3-cms.local.crt │ │ └── f3-cms.local.key ├── i18n │ └── .gitkeep ├── lib │ └── FFCMS │ │ ├── App.php │ │ ├── CLI.php │ │ ├── CLI │ │ ├── Base.php │ │ └── Index.php │ │ ├── Controllers │ │ ├── API │ │ │ ├── API.php │ │ │ ├── Audit.php │ │ │ ├── ConfigData.php │ │ │ ├── Mapper.php │ │ │ ├── OAuth2Apps.php │ │ │ ├── OAuth2Tokens.php │ │ │ ├── Reports.php │ │ │ ├── Token.php │ │ │ ├── Users.php │ │ │ └── UsersData.php │ │ ├── Admin │ │ │ ├── Admin.php │ │ │ ├── Apps.php │ │ │ ├── Audit.php │ │ │ ├── Config.php │ │ │ ├── Pages.php │ │ │ ├── Reports.php │ │ │ ├── Tokens.php │ │ │ ├── Users.php │ │ │ └── UsersData.php │ │ ├── Base.php │ │ ├── Index.php │ │ ├── Media │ │ │ └── Images │ │ │ │ └── Users.php │ │ ├── OAuth2 │ │ │ └── OAuth2.php │ │ ├── Pages │ │ │ ├── Contact.php │ │ │ └── Page.php │ │ └── User │ │ │ ├── Apps.php │ │ │ ├── Base.php │ │ │ ├── ForgotPassword.php │ │ │ └── User.php │ │ ├── Enums │ │ ├── ApiScopes.php │ │ ├── ApiStatuses.php │ │ ├── Bytes.php │ │ ├── ConfigTypes.php │ │ ├── Languages.php │ │ ├── PageCategories.php │ │ ├── PageStatuses.php │ │ ├── ProfileKeys.php │ │ ├── Scopes.php │ │ └── Statuses.php │ │ ├── Exceptions │ │ ├── Exception.php │ │ ├── InvalidArgumentException.php │ │ ├── LengthException.php │ │ └── UnexpectedValueException.php │ │ ├── Mappers │ │ ├── Assets.php │ │ ├── Audit.php │ │ ├── ConfigData.php │ │ ├── Mapper.php │ │ ├── OAuth2Apps.php │ │ ├── OAuth2Tokens.php │ │ ├── Pages.php │ │ ├── Reports.php │ │ ├── Users.php │ │ └── UsersData.php │ │ ├── Models │ │ ├── Assets.php │ │ ├── Audit.php │ │ ├── Base.php │ │ ├── ConfigData.php │ │ ├── DB.php │ │ ├── OAuth2.php │ │ └── Users.php │ │ ├── Setup.php │ │ └── Traits │ │ ├── Notification.php │ │ ├── SearchController.php │ │ ├── SecurityController.php │ │ ├── UrlHelper.php │ │ └── Validation.php └── templates │ └── en │ ├── cms │ └── cms │ │ ├── admin │ │ ├── apps │ │ │ ├── edit.phtml │ │ │ └── list.phtml │ │ ├── audit │ │ │ ├── list.phtml │ │ │ └── view.phtml │ │ ├── config.phtml │ │ ├── config │ │ │ ├── add.phtml │ │ │ ├── edit.phtml │ │ │ └── list.phtml │ │ ├── index.phtml │ │ ├── oauth2.phtml │ │ ├── pages │ │ │ ├── add.phtml │ │ │ ├── edit.phtml │ │ │ └── list.phtml │ │ ├── reports │ │ │ ├── add.phtml │ │ │ ├── edit.phtml │ │ │ ├── list.phtml │ │ │ └── view.phtml │ │ ├── tokens │ │ │ ├── edit.phtml │ │ │ └── list.phtml │ │ ├── users │ │ │ ├── edit.phtml │ │ │ └── list.phtml │ │ └── usersdata │ │ │ ├── add.phtml │ │ │ ├── edit.phtml │ │ │ └── list.phtml │ │ ├── footer-menu.phtml │ │ ├── footer.phtml │ │ ├── header-menu.phtml │ │ ├── header.phtml │ │ ├── notifications.phtml │ │ └── paginator.phtml │ ├── skin │ └── .gitkeep │ └── website │ ├── apps │ ├── apps.phtml │ └── docs.phtml │ ├── email │ ├── confirm_email.md │ └── forgot_password.md │ ├── error │ ├── 404.phtml │ ├── debug.phtml │ └── error.phtml │ ├── forgot_password │ ├── forgot_password_step1.phtml │ ├── forgot_password_step2.phtml │ └── forgot_password_step3.phtml │ ├── index │ ├── blank.phtml │ └── index.phtml │ ├── markdown-template.phtml │ ├── oauth2 │ ├── authenticate.phtml │ ├── callback.phtml │ ├── confirm.phtml │ └── deny.phtml │ ├── pages │ ├── contact.phtml │ └── page.phtml │ └── user │ ├── account.phtml │ ├── index.phtml │ ├── login.phtml │ ├── profile.phtml │ └── register.phtml ├── bin └── cli.php ├── composer.json ├── data ├── db │ ├── migrations │ │ ├── 20160713214419_users.php │ │ ├── 20160714152505_users_data.php │ │ ├── 20160715174200_audit.php │ │ ├── 20160717113500_config_data.php │ │ ├── 20160719215200_oauth2apps.php │ │ ├── 20160719222400_oauth2tokens.php │ │ ├── 20160805134100_reports.php │ │ ├── 20160829172800_assets.php │ │ └── 20160901181900_pages.php │ ├── seeds │ │ └── UserSeeder.php │ └── sql │ │ ├── audit-archive.sql │ │ ├── create.sql │ │ └── phinx.sql ├── phinx └── phinx.yml ├── docs ├── API.md ├── CLI.md ├── CREDITS.md ├── DATABASE.md ├── GUIDE.md ├── I18N.md ├── OAUTH2.md ├── ROADMAP.md ├── TESTING.md └── TODO.md ├── phpunit.xml ├── tests ├── .gitkeep ├── bootstrap.php ├── codeception.yml ├── setup.php ├── setuptest.php └── tests │ ├── _bootstrap.php │ ├── _data │ └── dump.sql │ ├── _support │ ├── AcceptanceTester.php │ ├── ApiTester.php │ ├── Helper │ │ ├── Acceptance.php │ │ ├── Api.php │ │ └── Unit.php │ ├── Step │ │ └── Acceptance │ │ │ ├── Admin.php │ │ │ └── Register.php │ ├── UnitTester.php │ └── _generated │ │ ├── AcceptanceTesterActions.php │ │ ├── ApiTesterActions.php │ │ └── UnitTesterActions.php │ ├── acceptance.suite.yml │ ├── acceptance │ ├── AdminLoginCept.php │ ├── AdminPagesCept.php │ ├── ForgotPasswordCept.php │ ├── MyAccountCept.php │ ├── RegisterAppCept.php │ ├── RegisterCept.php │ ├── UpdateMyAccountCept.php │ ├── WelcomeCept.php │ └── _bootstrap.php │ ├── api.suite.yml │ ├── api │ ├── GetUserBearerTokenCept.php │ ├── GetUserCept.php │ ├── GetUserClientCredentialsCept.php │ ├── TokenClientCredentialsCept.php │ ├── TokenPasswordCredentialsCept.php │ ├── TokenRefreshCept.php │ ├── TokenRevokeCept.php │ └── _bootstrap.php │ ├── unit.suite.yml │ └── unit │ └── _bootstrap.php ├── tmp ├── cache │ └── .gitkeep ├── logs │ └── .gitkeep ├── screenshot.png ├── sessions │ └── .gitkeep └── uploads │ └── .gitkeep └── www ├── .htaccess ├── 404.html ├── LICENSE ├── README.md ├── apple-touch-icon.png ├── browserconfig.xml ├── css ├── code.css ├── font-awesome.css ├── font-awesome.min.css ├── materialize.css ├── materialize.min.css └── style.css ├── favicon.ico ├── favicon.png ├── fonts ├── FontAwesome.otf ├── fontawesome-webfont.eot ├── fontawesome-webfont.svg ├── fontawesome-webfont.ttf ├── fontawesome-webfont.woff ├── fontawesome-webfont.woff2 └── roboto │ ├── Roboto-Bold.eot │ ├── Roboto-Bold.ttf │ ├── Roboto-Bold.woff │ ├── Roboto-Bold.woff2 │ ├── Roboto-Light.eot │ ├── Roboto-Light.ttf │ ├── Roboto-Light.woff │ ├── Roboto-Light.woff2 │ ├── Roboto-Medium.eot │ ├── Roboto-Medium.ttf │ ├── Roboto-Medium.woff │ ├── Roboto-Medium.woff2 │ ├── Roboto-Regular.eot │ ├── Roboto-Regular.ttf │ ├── Roboto-Regular.woff │ ├── Roboto-Regular.woff2 │ ├── Roboto-Thin.eot │ ├── Roboto-Thin.ttf │ ├── Roboto-Thin.woff │ └── Roboto-Thin.woff2 ├── humans.txt ├── img ├── favicon.png └── oauth.png ├── index.php ├── js ├── jquery.min.js ├── materialize.min.js ├── showdown.min.js ├── showdown.min.js.map └── site.js ├── robots.txt ├── tile-wide.png └── tile.png /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | # 4 space indentation 12 | [*.{json,php,phtml}] 13 | indent_size = 4 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Include your project-specific ignores in this file 2 | # Read about how to use .gitignore: https://help.github.com/articles/ignoring-files 3 | *.DS_Store 4 | *.bak 5 | *.lock 6 | *.old 7 | *.orig 8 | *.out 9 | *.swp 10 | *.tmp 11 | *~ 12 | .DS_Store 13 | .svn 14 | .vsphpignore 15 | /*.cache 16 | /*.puo 17 | /nbproject 18 | logs/* 19 | tmp/* 20 | nbproject 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/bcosca/fatfree-core"] 2 | path = lib/bcosca/fatfree-core 3 | url = https://github.com/bcosca/fatfree-core.git 4 | [submodule "lib/FFMVC"] 5 | path = lib/FFMVC 6 | url = https://github.com/vijinho/FFMVC.git 7 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | 3 | linting: true 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: php 4 | 5 | php: 6 | - "7.0" 7 | 8 | env: 9 | - COMPOSER_OPTS="--prefer-stable" 10 | 11 | script: 12 | - phpunit 13 | # - phpunit --coverage-text --coverage-clover=coverage.clover tests/Enums/RunTest.php 14 | 15 | before_script: 16 | - travis_retry composer self-update 17 | - travis_retry composer update $COMPOSER_OPTS 18 | 19 | #after_script: 20 | # - wget https://scrutinizer-ci.com/ocular.phar 21 | # - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 22 | 23 | install: 24 | - alias composer=composer\ -n && composer selfupdate 25 | - composer validate 26 | - composer --prefer-source install 27 | 28 | cache: 29 | directories: 30 | - $HOME/.composer/cache 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Application Releases 2 | 3 | # Version 0.0.1 - f3-cms created 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This Code of Conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting the project maintainer at vijay@yoyo.org. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident. 43 | 44 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 45 | version 1.3.0, available at 46 | [http://contributor-covenant.org/version/1/3/0/][version] 47 | 48 | [homepage]: http://contributor-covenant.org 49 | [version]: http://contributor-covenant.org/version/1/3/0/ 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | If you want to give me some feedback or make a suggestion, create an [issue on 2 | GitHub](https://github.com/vijinho/f3-cms/issues/new). 3 | 4 | If you want to get your hands dirty, great! Here's a couple of 5 | steps/guidelines: 6 | 7 | - Please have a look at the [docs/TODO](docs/TODO) to see if there's something you can help with. 8 | - Add tests for your changes (in `tests/`). 9 | - Remember to stick to the existing code style as best as possible. When in 10 | doubt, follow `PSR-2`. 11 | - Before investing a lot of time coding, create an issue to get our opinion on 12 | your big changes. 13 | - Update the documentation, if applicable. 14 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 2 | 3 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 4 | 5 | You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/gpl-3.0.html 6 | -------------------------------------------------------------------------------- /app/config/.gitignore: -------------------------------------------------------------------------------- 1 | config.ini 2 | -------------------------------------------------------------------------------- /app/config/config.example.ini: -------------------------------------------------------------------------------- 1 | [globals] 2 | DEBUG=4 3 | CACHE=true 4 | 5 | [app] 6 | version=0.0.1 7 | env=dev 8 | 9 | [security] 10 | csrf=true 11 | ; dns blacklist check used on auth pages if set 12 | ; dnsbl=b.barracudacentral.org,blacklist.sci.kun.nl,proxy.bl.gweep.ca,zen.spamhaus.org;bl.spamcop.net 13 | 14 | [db] 15 | dsn_http=mysql://root:root@127.0.0.1:3306/development_db 16 | dsn_test=mysql://root:root@127.0.0.1:3306/ffmvc_test_db 17 | 18 | [email] 19 | from=you@example.com 20 | from_name="Your Name" 21 | 22 | [api] 23 | version=0.0.1 24 | https=false 25 | 26 | [cfg] 27 | keys.load=contact-email,author-url 28 | keys.www=github-url,twitter-url,eyem-url,instagram-url 29 | 30 | [ttl] 31 | default=30 32 | blacklist=30 33 | doc=5 34 | error=5 35 | minify=30 36 | cfg=30 37 | -------------------------------------------------------------------------------- /app/config/routes-cli.ini: -------------------------------------------------------------------------------- 1 | [routes] 2 | ; routes used on the command-line 3 | GET / = \FFCMS\CLI\Index->index 4 | GET /@controller/@method = \FFCMS\CLI\@controller->@method 5 | GET /@controller/@method/@id = \FFCMS\CLI\@controller->@method 6 | GET /@controller/@method/* = \FFCMS\CLI\@controller->@method 7 | -------------------------------------------------------------------------------- /app/config/webserver/ssl/f3-cms.local.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICgTCCAeoCCQDrdcV4ChfCTDANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMC 3 | R0IxFjAUBgNVBAgTDVdlc3QgTWlkbGFuZHMxFjAUBgNVBAcTDVdvbHZlcmhhbXB0 4 | b24xDzANBgNVBAoTBmYzLWNtczEVMBMGA1UEAxMMZjMtY21zLmxvY2FsMR0wGwYJ 5 | KoZIhvcNAQkBFg5mM0BleGFtcGxlLmNvbTAeFw0xNjA3MTQxODIyNTBaFw0yNjA3 6 | MTIxODIyNTBaMIGEMQswCQYDVQQGEwJHQjEWMBQGA1UECBMNV2VzdCBNaWRsYW5k 7 | czEWMBQGA1UEBxMNV29sdmVyaGFtcHRvbjEPMA0GA1UEChMGZjMtY21zMRUwEwYD 8 | VQQDEwxmMy1jbXMubG9jYWwxHTAbBgkqhkiG9w0BCQEWDmYzQGV4YW1wbGUuY29t 9 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDAKj/KdAocv9Wgl9UpD1r2JyA 10 | Xs5dZtpHBd35RtLLqZ+oMQdPl3oYOVghPRTBaphEc+EBKEOobP69YeqE7ONjBN6u 11 | JPU4seEjHVz6jr49vs00ipQUvl/oQL+XK0GzaJZhXIcTKSL6CWPqaxtj0F5V8UhP 12 | 1XHGXscr89GaiXJ4ZQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAI67i5axgz6yMUSn 13 | nnPGZeCpY7jIeLad+a154JBnYwJuO5pITcrkj9LVyC3z09EByZEyQbkjUrZT01gn 14 | INHdU8zHPPTJ93xjkpiVTgSy6ZAtNrtAJVxxhWsWpsqNwkhJ4AAez5uy4/MUvugH 15 | 4WZ6azAYN5UririTBSh0XPN7CY7q 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /app/config/webserver/ssl/f3-cms.local.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQDDAKj/KdAocv9Wgl9UpD1r2JyAXs5dZtpHBd35RtLLqZ+oMQdP 3 | l3oYOVghPRTBaphEc+EBKEOobP69YeqE7ONjBN6uJPU4seEjHVz6jr49vs00ipQU 4 | vl/oQL+XK0GzaJZhXIcTKSL6CWPqaxtj0F5V8UhP1XHGXscr89GaiXJ4ZQIDAQAB 5 | AoGAC/PRZ/p3INOTpQjOsRB0F1Uqmo+1FHKGdI3+ghX+O6+E8rk2moFNYYi6RydI 6 | S2auOJvlsb13EC7GGnOS/VzLvx2WDITgOKXE1AHKwawu/9I3Hr6YxGXQg0Uw0X1g 7 | cpp2MqjF5I+7yPbCYvs+NajtWPvOPZoF5xgSPzmeTzgnsY0CQQDpMHMiBwzE1x9f 8 | /IWIJMIxrgxhgNIym9M9KNlSdfm/sqLyEV29/yfPZw8ozCec7yQlxkHbMCKx6oTO 9 | OiGj2Hz7AkEA1hPvf0hQonIZPZ1qk/jB5QIJA9MmFe+7LMCRepusun3VS+X6ZbNs 10 | GQR07wDawBWIhUOjRzWF+qdK8HijP0YiHwJBAK9aEZnq9z0mD5/cgoVoLuew2/qO 11 | JoKMDwMUrqeFs7LloAar7HQtZUBfXVTugHNQmTwWo/sxbUWg9xElQZq19vUCQQDJ 12 | jdV0ihpZB4HaMAZzMMclHQht0HPQPXiFxvxxanZy0xxqLCnXbNk+qKKLj8tlBCEY 13 | DzmARtVQzAdTZtGUNizTAkAamgXTWrG1gLArsjHJSjIEzb4CIYFBzMNM5BvxAbiD 14 | Shvy2e1rOuUoR2wfFJwKUx2wNr9J1pTisH5srL3NR3bj 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /app/i18n/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/app/i18n/.gitkeep -------------------------------------------------------------------------------- /app/lib/FFCMS/CLI.php: -------------------------------------------------------------------------------- 1 | get('CLI'))) { 22 | die('This can only be executed in CLI mode.'); 23 | } 24 | 25 | \FFMVC\App::start(); 26 | $f3->set('UNLOAD', function () { 27 | \FFMVC\App::finish(); 28 | }); 29 | 30 | // load dependency injection container 31 | $dice = new \Dice\Dice; 32 | 33 | // logging for application 34 | $logfile = $f3->get('log.file'); 35 | $dice->addRule('Log', ['shared' => true, 'constructParams' => [$logfile]]); 36 | 37 | // database connection used by app 38 | $dbConfig = $f3->get('db'); 39 | $dice->addRule('DB\\SQL', ['shared' => true, 'constructParams' => [ 40 | \FFMVC\Helpers\DB::createDbDsn($dbConfig), 41 | $dbConfig['user'], 42 | $dbConfig['pass'], 43 | [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION], 44 | ]]); 45 | 46 | // auto-create database if options set 47 | \FFCMS\Setup::database($dice); 48 | 49 | // run the main application 50 | require_once 'lib/FFCMS/App.php'; 51 | $app = $dice->create('FFCMS\\App'); 52 | $app->Main(); 53 | } 54 | 55 | // run the application 56 | boot(); 57 | -------------------------------------------------------------------------------- /app/lib/FFCMS/CLI/Base.php: -------------------------------------------------------------------------------- 1 | get('CLI'))) { 43 | exit("This controller can only be executed in CLI mode."); 44 | } 45 | 46 | $this->db = \Registry::get('db'); 47 | $this->logger = \Registry::get('logger'); 48 | $this->cli = new \League\CLImate\CLImate; 49 | } 50 | 51 | /** 52 | * @return void 53 | */ 54 | public function beforeRoute() 55 | { 56 | $cli = $this->cli; 57 | $cli->blackBoldUnderline("CLI Script"); 58 | } 59 | 60 | 61 | /** 62 | * @param \Base $f3 63 | * @return void 64 | */ 65 | public function afterRoute(\Base $f3) 66 | { 67 | $cli = $this->cli; 68 | $cli->shout('Finished.'); 69 | $cli->info('Script executed in ' . round(microtime(true) - $f3->get('TIME'), 3) . ' seconds.'); 70 | $cli->info('Memory used ' . round(memory_get_peak_usage() / 1024 / 1024, 2) . ' MB.'); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/lib/FFCMS/CLI/Index.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | */ 12 | class Index extends Base 13 | { 14 | /** 15 | * @return void 16 | */ 17 | public function index() 18 | { 19 | $cli = $this->cli; 20 | $cli->shoutBold(__METHOD__); 21 | $cli->shout('Hello World!'); 22 | } 23 | 24 | /** 25 | * example to test if already running 26 | * run cli.php '/index/running' in two different terminals 27 | * @return bool 28 | */ 29 | public function running() 30 | { 31 | $cli = $this->cli; 32 | $cli->shoutBold(__METHOD__); 33 | 34 | // use process id for log notifications 35 | $mypid = getmypid(); 36 | $pid = $mypid['PID']; 37 | $msg = $pid . ': Starting...'; 38 | $cli->shout($msg); 39 | 40 | // check if already running, quit if so 41 | exec('ps auxww | grep -i index/running | grep -v grep', $output); 42 | 43 | if (1 < count($output)) { 44 | $msg = $pid . ': Already running! Quitting.'; 45 | $cli->shout($msg); 46 | return false; 47 | } 48 | 49 | sleep(10); 50 | 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/API/Audit.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Audit extends Mapper 15 | { 16 | /** 17 | * Perform a create/update of the an item, used by POST, PUT, PATCH 18 | * 19 | * @param \Base $f3 20 | * @param array $prohibitedFields 21 | * @return void 22 | */ 23 | private function save(\Base $f3, array $prohibitedFields = []) 24 | { 25 | // set audit user if not set 26 | $data = $f3->get('REQUEST'); 27 | $user = $f3->get('user'); 28 | 29 | // set uuid from user 30 | if (!array_key_exists('users_uuid', $data)) { 31 | $data['users_uuid'] = $user['uuid']; 32 | } 33 | 34 | // set actor from email 35 | if (!array_key_exists('actor', $data)) { 36 | $data['actor'] = $user['email']; 37 | } 38 | 39 | // do not allow request to define these fields: 40 | foreach ($prohibitedFields as $field) { 41 | if (array_key_exists($field, $data)) { 42 | unset($data[$field]); 43 | } 44 | } 45 | 46 | // load pre-existing value 47 | $m = $this->getMapper(); 48 | 49 | // copy data and validate 50 | $m->copyfrom($data); 51 | $m->validationRequired([ 52 | 'users_uuid' 53 | ]); 54 | 55 | $errors = $m->validate(false); 56 | if (true !== $errors) { 57 | foreach ($errors as $error) { 58 | $this->setOAuthError('invalid_request'); 59 | $this->failure($error['field'], $error['rule']); 60 | } 61 | } else { 62 | // load original record, ovewrite 63 | if (!empty($data['uuid'])) { 64 | $m->load(['uuid = ?', $data['uuid']]); 65 | } 66 | $m->copyfrom($data); 67 | 68 | // load in original data and then replace for save 69 | if (!$m->save()) { 70 | $this->setOAuthError('invalid_request'); 71 | $this->failure('error', 'Unable to update object.'); 72 | return; 73 | } 74 | 75 | // return raw data for object? 76 | $adminView = $f3->get('isAdmin') && 'admin' == $f3->get('REQUEST.view'); 77 | $this->data = $adminView ? $m->castFields($f3->get('REQUEST.fields')) : $m->exportArray($f3->get('REQUEST.fields')); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/API/ConfigData.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Vijay Mahrra 13 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 14 | */ 15 | class ConfigData extends Mapper 16 | { 17 | /** 18 | * Perform a create/update of the an item, used by POST, PUT, PATCH 19 | * 20 | * @param \Base $f3 21 | * @param array $prohibitedFields 22 | * @return void 23 | */ 24 | private function save(\Base $f3, array $prohibitedFields = []) 25 | { 26 | // do not allow request to define these fields: 27 | $data = $f3->get('REQUEST'); 28 | foreach ($prohibitedFields as $field) { 29 | if (array_key_exists($field, $data)) { 30 | unset($data[$field]); 31 | } 32 | } 33 | 34 | // load pre-existing value 35 | $m = $this->getMapper(); 36 | 37 | // copy data and validate 38 | $m->copyfrom($data); 39 | $m->validationRequired([ 40 | 'key', 'value', 'type', 'rank' 41 | ]); 42 | 43 | $errors = $m->validate(false); 44 | if (true !== $errors) { 45 | foreach ($errors as $error) { 46 | $this->setOAuthError('invalid_request'); 47 | $this->failure($error['field'], $error['rule']); 48 | } 49 | } else { 50 | // load original record, ovewrite 51 | if ($f3->get('VERB') == 'PUT') { 52 | $m->load(['uuid = ?', $data['uuid']]); 53 | } else { 54 | $m->load([$m->quotekey('key') . ' = ?', $data['key']]); 55 | } 56 | $m->copyfrom($data); 57 | 58 | // load in original data and then replace for save 59 | if (!$m->save()) { 60 | $this->setOAuthError('invalid_request'); 61 | $this->failure('error', 'Unable to update object.'); 62 | return; 63 | } 64 | 65 | // return raw data for object? 66 | $adminView = $f3->get('isAdmin') && 'admin' == $f3->get('REQUEST.view'); 67 | $this->data = $adminView ? $m->castFields($f3->get('REQUEST.fields')) : $m->exportArray($f3->get('REQUEST.fields')); 68 | } 69 | } 70 | 71 | 72 | /** 73 | * Update data 74 | * 75 | * @param \Base $f3 76 | * @param array $params 77 | * @return null|array|boolean 78 | */ 79 | public function patch(\Base $f3, array $params) 80 | { 81 | $m = $this->getIdObjectIfAdmin($f3, $params, 'uuid', $params['id']); 82 | if (!is_object($m) || null == $m->uuid) { 83 | return; 84 | } 85 | 86 | $f3->set('REQUEST.key', $m->key); 87 | 88 | // these fields can't be modified 89 | return $this->save($f3, [ 90 | 'id', 'uuid' 91 | ]); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/API/Reports.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Vijay Mahrra 14 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 15 | */ 16 | class Reports extends UsersData 17 | { 18 | protected $adminOnly = true; 19 | 20 | 21 | /** 22 | * Perform a create/update of the an item, used by POST, PUT, PATCH 23 | * 24 | * @param \Base $f3 25 | * @param array $prohibitedFields 26 | * @return void 27 | */ 28 | protected function save(\Base $f3, array $prohibitedFields = []) 29 | { 30 | // do not allow request to define these fields: 31 | $data = $f3->get('REQUEST'); 32 | foreach ($prohibitedFields as $field) { 33 | if (array_key_exists($field, $data)) { 34 | unset($data[$field]); 35 | } 36 | } 37 | 38 | // load pre-existing value 39 | $m = $this->getMapper(); 40 | if ($f3->get('VERB') == 'PUT') { 41 | $m->load(['uuid = ?', $data['uuid']]); 42 | } else { 43 | $m->load(['users_uuid = ? AND ' . $m->quotekey('key') . ' = ?', $data['users_uuid'], $data['key']]); 44 | } 45 | 46 | // copy data and validate 47 | $m->copyfrom($data); 48 | $m->validationRequired([ 49 | 'users_uuid', 'key', 'name', 'query' 50 | ]); 51 | $errors = $m->validate(false); 52 | if (true !== $errors) { 53 | foreach ($errors as $error) { 54 | $this->setOAuthError('invalid_request'); 55 | $this->failure($error['field'], $error['rule']); 56 | } 57 | } else { 58 | // load in original data and then replace for save 59 | if (!$m->save()) { 60 | $this->setOAuthError('invalid_request'); 61 | $this->failure('error', 'Unable to update object.'); 62 | return; 63 | } 64 | 65 | // return raw data for object? 66 | $adminView = $f3->get('isAdmin') && 'admin' == $f3->get('REQUEST.view'); 67 | $this->data = $adminView ? $m->castFields($f3->get('REQUEST.fields')) : $m->exportArray($f3->get('REQUEST.fields')); 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/Admin/Admin.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) Copyright 2016 Vijay Mahrra 15 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 16 | */ 17 | class Admin extends Controllers\User\Base 18 | { 19 | /** 20 | * Logout if not admin 21 | * 22 | * @param \Base $f3 23 | * @param array $params 24 | * @return void 25 | */ 26 | public function beforeRoute(\Base $f3, array $params) 27 | { 28 | parent::beforeRoute($f3, $params); 29 | 30 | // non-admin user gets logged out 31 | if (false == $f3->get('isAdmin')) { 32 | $f3->reroute('@logout'); 33 | } 34 | 35 | $this->redirectLoggedOutUser(); 36 | } 37 | 38 | /** 39 | * 40 | * 41 | * @return void 42 | */ 43 | public function index() 44 | { 45 | $this->redirectLoggedOutUser(); 46 | 47 | echo \View::instance()->render('cms/admin/index.phtml'); 48 | } 49 | 50 | 51 | /** 52 | * 53 | * 54 | * @return void 55 | */ 56 | public function phpinfo() 57 | { 58 | phpinfo(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/Admin/Audit.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2016 Vijay Mahrra 13 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 14 | */ 15 | class Audit extends Admin 16 | { 17 | /** 18 | * For admin listing and search results 19 | */ 20 | use Traits\SearchController; 21 | 22 | protected $template_path = 'cms/admin/audit/'; 23 | 24 | /** 25 | * 26 | * 27 | * @param \Base $f3 28 | * @return void 29 | */ 30 | public function listing(\Base $f3) 31 | { 32 | $view = strtolower(trim(strip_tags($f3->get('REQUEST.view')))); 33 | $view = empty($view) ? 'list.phtml' : $view . '.phtml'; 34 | $f3->set('REQUEST.view', $view); 35 | 36 | $f3->set('results', $this->getListingResults($f3, new Mappers\Audit)); 37 | 38 | $f3->set('breadcrumbs', [ 39 | _('Admin') => 'admin', 40 | _('Audit') => 'admin_audit_list', 41 | ]); 42 | 43 | $f3->set('form', $f3->get('REQUEST')); 44 | echo \View::instance()->render($this->template_path . $view); 45 | } 46 | 47 | 48 | /** 49 | * 50 | * 51 | * @param \Base $f3 52 | * @return void 53 | */ 54 | public function search(\Base $f3) 55 | { 56 | $view = strtolower(trim(strip_tags($f3->get('REQUEST.view')))); 57 | $view = empty($view) ? 'list.phtml' : $view . '.phtml'; 58 | $f3->set('REQUEST.view', $view); 59 | 60 | $f3->set('results', $this->getSearchResults($f3, new Mappers\Audit)); 61 | 62 | $f3->set('breadcrumbs', [ 63 | _('Admin') => 'admin', 64 | _('Audit') => 'admin_audit_list', 65 | _('Search') => '', 66 | ]); 67 | 68 | $f3->set('form', $f3->get('REQUEST')); 69 | echo \View::instance()->render($this->template_path . $view); 70 | } 71 | 72 | /** 73 | * 74 | * 75 | * @param \Base $f3 76 | * @return void 77 | */ 78 | public function view(\Base $f3) 79 | { 80 | $this->redirectLoggedOutUser(); 81 | 82 | if (false == $f3->get('isRoot')) { 83 | $this->notify(_('You do not have (root) permission!'), 'error'); 84 | return $f3->reroute('@admin'); 85 | } 86 | 87 | $auditModel = Models\Audit::instance(); 88 | $auditMapper = $auditModel->getMapper(); 89 | 90 | $uuid = $f3->get('REQUEST.uuid'); 91 | $auditMapper->load(['uuid = ?', $uuid]); 92 | 93 | $f3->set('breadcrumbs', [ 94 | _('Admin') => 'admin', 95 | _('Audit') => 'admin_audit_list', 96 | _('View') => 'admin_audit_list', 97 | ]); 98 | 99 | $f3->set('form', $auditMapper->cast()); 100 | 101 | echo \View::instance()->render($this->template_path . 'view.phtml'); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/Index.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | */ 12 | class Index extends Base 13 | { 14 | /** 15 | * 16 | * 17 | * @param \Base $f3 18 | * @return void 19 | */ 20 | public function index(\Base $f3) 21 | { 22 | $f3->set('form', $f3->get('REQUEST')); 23 | echo \View::instance()->render('index/index.phtml'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/Media/Images/Users.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Users 15 | { 16 | /** 17 | * 18 | * 19 | * @param \Base $f3 20 | * @param array $params 21 | * @return string|null 22 | */ 23 | public function profile(\Base $f3, array $params = []) 24 | { 25 | // get asset table entry 26 | $asset = new Mappers\Assets; 27 | $asset->load(['users_uuid = ? AND ' . $asset->quotekey('key') . ' = ?', $params['uuid'], $params['key']]); 28 | if (null === $asset->uuid) { 29 | return $f3->status(404); 30 | } 31 | 32 | // get image dimensions 33 | $max = $f3->get('assets.image.max'); 34 | $height = abs((int) $f3->get('REQUEST.height')); 35 | $width = abs((int) $f3->get('REQUEST.width')); 36 | 37 | // If $crop is TRUE the image will be resized to fit with its smallest side into the resize box 38 | $crop = true; 39 | if (empty($height) || empty($width)) { 40 | // resize on longest side 41 | if ($height > $width) { 42 | $width = $height; 43 | } elseif ($width > $height) { 44 | $height = $width; 45 | } else { 46 | // use default height/width if missing 47 | $height = $f3->get('assets.image.default.height'); 48 | $width = $f3->get('assets.image.default.width'); 49 | } 50 | } elseif ($width > $max['width'] || $height > $max['height']) { 51 | // make sure maximum width/height not exceeded 52 | $height = $height > $max['height'] ? $max['height'] : $height; 53 | $width = $width > $max['width'] ? $max['width'] : $width; 54 | } 55 | 56 | // load user mapper 57 | $usersMapper = new Mappers\Users; 58 | $usersMapper->load($params['uuid']); 59 | 60 | // work out filename 61 | //$hash = $f3->hash($asset); // generate unique hash for asset 62 | $filename = 'profile_' . $width . 'x' . $height . '.jpg'; 63 | 64 | // return the url if exists 65 | $url = $usersMapper->profileImageUrl($filename); 66 | if (!empty($url)) { 67 | return $f3->reroute($url); 68 | } 69 | 70 | // 404 if the original asset file does not exist 71 | if (!file_exists($asset->filename)) { 72 | return $f3->status(404); 73 | } 74 | 75 | // create new resized file 76 | $img = new \Image($asset->filename); 77 | $img->resize($width, $height, $crop); 78 | if (empty($f3->write($usersMapper->profileImageFilePath($filename), $img->dump('jpeg', $f3->get('assets.image.default.quality.jpg'))))) { 79 | return $f3->status(404); 80 | } 81 | 82 | // serve the generated image via the web 83 | return $f3->reroute($url); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/Pages/Contact.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright (c) Copyright 2016 Vijay Mahrra 13 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 14 | */ 15 | class Contact extends Base 16 | { 17 | protected $template_path = 'pages/'; 18 | 19 | /** 20 | * Make contact page 21 | * 22 | * @param \Base $f3 23 | * @param array $params 24 | * @return void 25 | */ 26 | public function contact(\Base $f3, array $params = []) 27 | { 28 | $page = new Mappers\Pages; 29 | $page->load(['slug = ?', 'contact']); 30 | 31 | // conditions if page is viewable 32 | $publishTime = strtotime($page->published); 33 | $expireTime = strtotime($page->expires); 34 | $showPage = $f3->get('REQUEST.preview') || ( 35 | 'published' == $page->status && 36 | 'public' == $page->scopes && 37 | 'page' == $page->category && 38 | time() > $publishTime && 39 | (0 >= $expireTime || $expireTime > time()) 40 | ); 41 | 42 | if (!$showPage) { 43 | // 404 44 | echo 'page unavailable'; 45 | die(404); 46 | } 47 | 48 | $f3->set('pagesMapper', $page); 49 | 50 | echo \View::instance()->render($this->template_path . '/contact.phtml'); 51 | } 52 | 53 | /** 54 | * Contact page form post handler 55 | * 56 | * @param \Base $f3 57 | * @param array $params 58 | * @return void 59 | */ 60 | public function contactPost(\Base $f3, array $params = []) 61 | { 62 | // handle form input, send email 63 | 64 | echo \View::instance()->render($this->template_path . '/contact.phtml'); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/Pages/Page.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright (c) Copyright 2016 Vijay Mahrra 13 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 14 | */ 15 | class Page extends Base 16 | { 17 | protected $template_path = 'pages/'; 18 | 19 | /** 20 | * Render a published page unless not published yet 21 | * 22 | * @param \Base $f3 23 | * @param array $params 24 | * @return void 25 | */ 26 | public function page(\Base $f3, array $params = []) 27 | { 28 | if (array_key_exists('slug', $params)) { 29 | $slug = $params['slug']; 30 | } elseif (preg_match('/^\/(?P[^\/]+)\/(?P.+)/', $f3->get('PATH'), $matches)) { 31 | // split /XX/path/to/slug -> slug 32 | $parts = preg_split('/[\/]+/', $matches['path']); 33 | $slug = $parts[count($parts) - 1]; 34 | } else { 35 | // 404 36 | echo 'missing slug'; 37 | die(404); 38 | } 39 | 40 | if (empty($slug)) { 41 | // 404 42 | echo 'page does not exist'; 43 | die(404); 44 | } 45 | 46 | $page = new Mappers\Pages; 47 | $page->load(['slug = ?', $slug]); 48 | 49 | // conditions if page is viewable 50 | $publishTime = strtotime($page->published); 51 | $expireTime = strtotime($page->expires); 52 | $showPage = $f3->get('REQUEST.preview') || ( 53 | 'published' == $page->status && 54 | 'public' == $page->scopes && 55 | 'page' == $page->category && 56 | time() > $publishTime && 57 | (0 >= $expireTime || $expireTime > time()) 58 | ); 59 | 60 | if (!$showPage) { 61 | // 404 62 | echo 'page unavailable'; 63 | die(404); 64 | } 65 | 66 | $f3->set('pagesMapper', $page); 67 | 68 | echo \View::instance()->render($this->template_path . '/page.phtml'); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Controllers/User/Base.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright (c) Copyright 2016 Vijay Mahrra 15 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 16 | */ 17 | abstract class Base extends Controllers\Base 18 | { 19 | use Traits\SecurityController; 20 | 21 | /** 22 | * perform a client logout 23 | * 24 | * @param \Base $f3 25 | */ 26 | protected function doLogout(\Base $f3) 27 | { 28 | $uuid = $f3->get('uuid'); 29 | $f3->clear('SESSION'); 30 | $f3->clear('uuid'); 31 | if (!empty($uuid)) { 32 | Models\Users::instance()->logout($uuid); 33 | } 34 | } 35 | 36 | 37 | /** 38 | * logout for api users 39 | * 40 | * @param \Base $f3 41 | * @return void 42 | */ 43 | public function logout(\Base $f3) 44 | { 45 | $this->doLogout($f3); 46 | $this->notify(_('You are now logged out!'), 'success'); 47 | $f3->reroute('@index'); 48 | } 49 | 50 | 51 | /** 52 | * show login screen form 53 | * 54 | * @param \Base $f3 55 | * @return void 56 | */ 57 | public function login(\Base $f3) 58 | { 59 | $this->dnsbl(); 60 | $this->redirectLoggedInUser(); 61 | $this->csrf('@user'); 62 | $f3->set('form', $f3->get('REQUEST')); 63 | echo \View::instance()->render('user/login.phtml'); 64 | } 65 | 66 | 67 | /** 68 | * Redirect the user to the url if logged in 69 | * 70 | * @param string $url 71 | * @param array $params 72 | * @return void 73 | */ 74 | protected function redirectLoggedInUser(string $url = '@user', array $params = []) 75 | { 76 | $f3 = \Base::instance(); 77 | 78 | if (empty($params)) { 79 | $params = $f3->get('REQUEST'); 80 | } 81 | 82 | // do not redirect the php session name 83 | $session_name = session_name(); 84 | 85 | if (array_key_exists($session_name, $params)) { 86 | unset($params[$session_name]); 87 | } 88 | 89 | if (!empty($f3->get('uuid'))) { 90 | $f3->reroute($this->url($url, $params)); 91 | } 92 | } 93 | 94 | 95 | /** 96 | * Redirect the user to the url if logged out 97 | * 98 | * @param string $url 99 | * @param array $params 100 | * @return void 101 | */ 102 | protected function redirectLoggedOutUser(string $url = '@login', array $params = []) 103 | { 104 | $f3 = \Base::instance(); 105 | 106 | if (empty($params)) { 107 | $params = $f3->get('REQUEST'); 108 | } 109 | 110 | // do not redirect the php session name 111 | $session_name = session_name(); 112 | 113 | if (array_key_exists($session_name, $params)) { 114 | unset($params[$session_name]); 115 | } 116 | 117 | if (empty($f3->get('uuid'))) { 118 | $f3->reroute($this->url($url, $params)); 119 | } 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/ApiScopes.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class ApiScopes extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = true; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'read' => 'Read any of your personal data', 37 | 'write' => 'Edit all of your personal data', 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/ApiStatuses.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class ApiStatuses extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = true; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'registered', 37 | 'confirmed', 38 | 'suspended', 39 | 'cancelled', 40 | 'closed', 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/Bytes.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Bytes extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = true; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'bit' => 1, 37 | 'byte' => 8, 38 | 'kilobyte' => 8 * 1024, 39 | 'megabyte' => 8 * 1024 * 1024, 40 | 'gigabyte' => 8 * 1024 * 1024 * 1024, 41 | 'terabyte' => 8 * 1024 * 1024 * 1024 * 1024, 42 | ]; 43 | } 44 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/ConfigTypes.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class ConfigTypes extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = false; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'text' => 'Text', 37 | 'textarea' => 'Textarea', 38 | 'url' => 'URL', 39 | 'email' => 'Email', 40 | 'html' => 'HTML', 41 | 'markdown' => 'Markdown', 42 | 'json' => 'JSON', 43 | 'yaml' => 'YAML', 44 | 'numeric' => 'Numeric', 45 | 'whole_number' => 'Whole Number', 46 | 'integer' => 'Integer', 47 | 'float' => 'Float', 48 | 'boolean' => 'Boolean', 49 | 'float' => 'Float', 50 | 'date' => 'Date', 51 | ]; 52 | } 53 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/Languages.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Languages extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = false; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'en' => 'English', 37 | 'es' => 'Spanish', 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/PageCategories.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class PageCategories extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = false; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'page' => 'Page', 37 | 'news' => 'News', 38 | 'blog' => 'Blog', 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/PageStatuses.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class PageStatuses extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = true; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'draft', 37 | 'review', 38 | 'published', 39 | 'unpublished', 40 | 'expired', 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/ProfileKeys.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class ProfileKeys extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = false; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'nickname', 37 | 'bio', 38 | 'image', 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/Scopes.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Scopes extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = true; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'root', 37 | 'admin', 38 | 'api', 39 | 'user', 40 | 'public', 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Enums/Statuses.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Statuses extends Enum 15 | { 16 | /** 17 | * always capitalize enum keys? 18 | * 19 | * @var bool 20 | */ 21 | protected static $capitalize = true; 22 | 23 | /** 24 | * case-sensitive check when searching by key for a value? 25 | * 26 | * @var bool 27 | */ 28 | protected static $case_sensitive = false; 29 | 30 | /** 31 | * enum values 32 | * 33 | * @var array $values 34 | */ 35 | protected static $values = [ 36 | 'registered', 37 | 'confirmed', 38 | 'suspended', 39 | 'cancelled', 40 | 'closed', 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Exceptions/Exception.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $uuid 14 | * @property string $users_uuid 15 | * @property string $key 16 | * @property string $groups 17 | * @property string $name 18 | * @property string $description 19 | * @property string $filename 20 | * @property string $url 21 | * @property string $type 22 | * @property string $size 23 | * @property string $tags 24 | * @property string $categories 25 | * @property string $metadata 26 | * @property string $created 27 | */ 28 | class Assets extends Mapper 29 | { 30 | /** 31 | * Fields and their visibility to clients, boolean or string of visible field name 32 | * 33 | * @var array $fieldsVisible 34 | * @link https://github.com/Wixel/GUMP 35 | */ 36 | public $fieldsVisible = [ 37 | 'uuid' => 'id', 38 | 'users_uuid' => 'user_id', 39 | 'filename' => false, 40 | ]; 41 | 42 | /** 43 | * Fields that are editable to clients, boolean or string of visible field name 44 | * 45 | * @var array $fieldsEditable 46 | */ 47 | protected $fieldsEditable = [ 48 | 'key', 49 | 'groups', 50 | 'name', 51 | 'description', 52 | 'categories', 53 | 'tags', 54 | 'url', 55 | 'metadata', 56 | ]; 57 | 58 | /** 59 | * Filter rules for fields 60 | * 61 | * @var array $filterRules 62 | * @link https://github.com/Wixel/GUMP 63 | */ 64 | public $filterRules = [ 65 | 'uuid' => 'trim|sanitize_string|lower', 66 | 'users_uuid' => 'trim|sanitize_string|lower', 67 | 'key' => 'trim|sanitize_string|lower|slug', 68 | 'groups' => 'trim|sanitize_string|lower|slug', 69 | 'name' => 'trim|sanitize_string', 70 | 'description' => 'trim|sanitize_string', 71 | 'filename' => 'trim|sanitize_string|lower', 72 | 'url' => 'trim', 73 | 'type' => 'trim|sanitize_string|lower', 74 | 'size' => 'whole_number', 75 | 'categories' => 'trim|sanitize_string', 76 | 'tags' => 'trim|sanitize_string|lower', 77 | 'metadata' => 'trim', 78 | 'created' => 'trim|sanitize_string', 79 | 'updated' => 'trim|sanitize_string', 80 | ]; 81 | 82 | /** 83 | * Validation rules for fields 84 | * 85 | * @var array $validationRules 86 | * @link https://github.com/Wixel/GUMP 87 | */ 88 | public $validationRules = [ 89 | 'uuid' => 'alpha_dash', 90 | 'users_uuid' => 'alpha_dash', 91 | ]; 92 | } 93 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Mappers/Audit.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $uuid 14 | * @property string $users_uuid 15 | * @property string $created 16 | * @property string $actor 17 | * @property string $event 18 | * @property string $description 19 | * @property string $ip 20 | * @property string $old 21 | * @property string $new 22 | * @property string $debug 23 | */ 24 | class Audit extends Mapper 25 | { 26 | /** 27 | * Fields and their visibility to clients, boolean or string of visible field name 28 | * 29 | * @var array $fieldsVisible 30 | */ 31 | public $fieldsVisible = [ 32 | 'uuid' => 'id', 33 | 'users_uuid' => 'user_id', 34 | ]; 35 | 36 | /** 37 | * Filter rules for fields 38 | * 39 | * @var array $filterRules 40 | * @link https://github.com/Wixel/GUMP 41 | */ 42 | public $filterRules = [ 43 | 'uuid' => 'trim|sanitize_string|lower', 44 | 'users_uuid' => 'trim|sanitize_string|lower', 45 | 'created' => 'trim|sanitize_string', 46 | 'actor' => 'trim|sanitize_string', 47 | 'event' => 'trim|sanitize_string|upper|slug', 48 | 'description' => 'trim|sanitize_string', 49 | 'ip' => 'trim|sanitize_string', 50 | 'agent' => 'trim|sanitize_string', 51 | 'old' => 'trim', 52 | 'new' => 'trim', 53 | 'debug' => 'trim', 54 | ]; 55 | 56 | /** 57 | * Validation rules for fields 58 | * 59 | * @var array $validationRules 60 | * @link https://github.com/Wixel/GUMP 61 | */ 62 | public $validationRules = [ 63 | 'uuid' => 'alpha_dash', 64 | 'users_uuid' => 'alpha_dash', 65 | ]; 66 | } 67 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Mappers/ConfigData.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $uuid 14 | * @property string $description 15 | * @property string $key 16 | * @property string $value 17 | * @property string $type 18 | * @property string $options 19 | * @property string $rank 20 | */ 21 | class ConfigData extends Mapper 22 | { 23 | /** 24 | * Fields and their visibility to clients, boolean or string of visible field name 25 | * 26 | * @var array $fieldsVisible 27 | */ 28 | public $fieldsVisible = [ 29 | 'uuid' => 'id', 30 | ]; 31 | 32 | /** 33 | * Filter rules for fields 34 | * 35 | * @var array $filterRules 36 | * @link https://github.com/Wixel/GUMP 37 | */ 38 | public $filterRules = [ 39 | 'uuid' => 'trim|sanitize_string|lower', 40 | 'description' => 'trim|sanitize_string', 41 | 'key' => 'trim|sanitize_string|lower|slug', 42 | 'value' => 'trim', 43 | 'type' => 'trim|sanitize_string|lower', 44 | 'options' => 'trim', 45 | 'rank' => 'sanitize_numbers|whole_number', 46 | ]; 47 | 48 | /** 49 | * Validation rules for fields 50 | * 51 | * @var array $validationRules 52 | * @link https://github.com/Wixel/GUMP 53 | */ 54 | public $validationRules = [ 55 | 'uuid' => 'alpha_dash', 56 | ]; 57 | } 58 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Mappers/OAuth2Apps.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $created 14 | * @property string $users_uuid 15 | * @property string $client_id 16 | * @property string $client_secret 17 | * @property string $name 18 | * @property string $logo_url 19 | * @property string $description 20 | * @property string $scope 21 | * @property string $callback_uri 22 | * @property string $redirect_uris 23 | * @property string $status 24 | */ 25 | class OAuth2Apps extends Mapper 26 | { 27 | protected $table = 'oauth2_apps'; 28 | 29 | /** 30 | * Fields and their visibility to clients, boolean or string of visible field name 31 | * 32 | * @var array $fieldsVisible 33 | */ 34 | public $fieldsVisible = [ 35 | 'users_uuid' => 'user_id', 36 | 'client_id' => 'id', 37 | ]; 38 | 39 | /** 40 | * Filter rules for fields 41 | * 42 | * @var array $filterRules 43 | * @link https://github.com/Wixel/GUMP 44 | */ 45 | public $filterRules = [ 46 | 'created' => 'trim|sanitize_string', 47 | 'users_uuid' => 'trim|sanitize_string|lower', 48 | 'client_id' => 'trim|sanitize_string|lower', 49 | 'client_secret' => 'trim|sanitize_string|lower', 50 | 'name' => 'trim|sanitize_string', 51 | 'logo_url' => 'trim|urldecode', 52 | 'description' => 'trim|sanitize_string', 53 | 'scope' => 'trim|sanitize_string', 54 | 'callback_uri' => 'trim|urldecode', 55 | 'redirect_uris' => 'trim|urldecode', 56 | 'status' => 'trim|sanitize_string', 57 | ]; 58 | 59 | /** 60 | * Validation rules for fields 61 | * 62 | * @var array $validationRules 63 | * @link https://github.com/Wixel/GUMP 64 | */ 65 | public $validationRules = [ 66 | 'users_uuid' => 'alpha_dash', 67 | 'client_id' => 'alpha_dash', 68 | 'client_secret' => 'alpha_dash', 69 | 'logo_url' => 'valid_url', 70 | 'callback_uri' => 'valid_url', 71 | ]; 72 | } 73 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Mappers/OAuth2Tokens.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $uuid 14 | * @property string $created 15 | * @property string $expires 16 | * @property string $users_uuid 17 | * @property string $client_id 18 | * @property string $token 19 | * @property string $type 20 | * @property string $description 21 | * @property string $scope 22 | */ 23 | class OAuth2Tokens extends Mapper 24 | { 25 | /** 26 | * This one is guessed wrong! 27 | * @var type 28 | */ 29 | protected $table = 'oauth2_tokens'; 30 | 31 | /** 32 | * types of token 33 | * 34 | * @var type 35 | */ 36 | public $types = [ 37 | 'code', 38 | 'access_token', 39 | 'refresh_token', 40 | ]; 41 | 42 | /** 43 | * Fields and their visibility to clients, boolean or string of visible field name 44 | * 45 | * @var array $fieldsVisible 46 | */ 47 | public $fieldsVisible = [ 48 | 'uuid' => 'id', 49 | 'users_uuid' => 'user_id', 50 | ]; 51 | 52 | /** 53 | * Filter rules for fields 54 | * 55 | * @var array $filterRules 56 | * @link https://github.com/Wixel/GUMP 57 | */ 58 | public $filterRules = [ 59 | 'uuid' => 'trim|sanitize_string|lower', 60 | 'created' => 'trim|sanitize_string', 61 | 'expires' => 'trim|sanitize_string', 62 | 'users_uuid' => 'trim|sanitize_string|lower', 63 | 'client_id' => 'trim|sanitize_string|lower', 64 | 'token' => 'trim|sanitize_string', 65 | 'type' => 'trim|sanitize_string', 66 | 'description' => 'trim|sanitize_string', 67 | 'scope' => 'trim|sanitize_string', 68 | ]; 69 | 70 | /** 71 | * Validation rules for fields 72 | * 73 | * @var array $validationRules 74 | * @link https://github.com/Wixel/GUMP 75 | */ 76 | public $validationRules = [ 77 | 'uuid' => 'alpha_dash', 78 | 'users_uuid' => 'alpha_dash', 79 | 'client_id' => 'alpha_dash', 80 | 'type' => 'min_len,4', 81 | ]; 82 | } 83 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Mappers/Reports.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $uuid 14 | * @property string $users_uuid 15 | * @property string $scopes 16 | * @property string $key 17 | * @property string $name 18 | * @property string $description 19 | * @property string $query 20 | * @property string $created 21 | */ 22 | class Reports extends Mapper 23 | { 24 | /** 25 | * Fields and their visibility to clients, boolean or string of visible field name 26 | * 27 | * @var array $fieldsVisible 28 | * @link https://github.com/Wixel/GUMP 29 | */ 30 | public $fieldsVisible = [ 31 | 'uuid' => 'id', 32 | 'users_uuid' => 'user_id', 33 | 'query' => false, 34 | ]; 35 | 36 | /** 37 | * Fields that are editable to clients, boolean or string of visible field name 38 | * 39 | * @var array $fieldsEditable 40 | */ 41 | protected $fieldsEditable = [ 42 | 'name', 43 | 'description', 44 | 'query', 45 | ]; 46 | 47 | /** 48 | * Filter rules for fields 49 | * 50 | * @var array $filterRules 51 | * @link https://github.com/Wixel/GUMP 52 | */ 53 | public $filterRules = [ 54 | 'uuid' => 'trim|sanitize_string|lower', 55 | 'users_uuid' => 'trim|sanitize_string|lower', 56 | 'scopes' => 'trim|sanitize_string|lower', 57 | 'key' => 'trim|sanitize_string|lower|slug', 58 | 'name' => 'trim|sanitize_string', 59 | 'description' => 'trim|sanitize_string', 60 | 'query' => 'trim|sanitize_string', 61 | 'created' => 'trim|sanitize_string', 62 | ]; 63 | 64 | /** 65 | * Validation rules for fields 66 | * 67 | * @var array $validationRules 68 | * @link https://github.com/Wixel/GUMP 69 | */ 70 | public $validationRules = [ 71 | 'uuid' => 'alpha_dash', 72 | 'users_uuid' => 'alpha_dash', 73 | ]; 74 | } 75 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Mappers/UsersData.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | * 12 | * @property int $id 13 | * @property string $uuid 14 | * @property string $users_uuid 15 | * @property string $key 16 | * @property string $value 17 | * @property string $type 18 | */ 19 | class UsersData extends Mapper 20 | { 21 | /** 22 | * Fields and their visibility to clients, boolean or string of visible field name 23 | * 24 | * @var array $fieldsVisible 25 | * @link https://github.com/Wixel/GUMP 26 | */ 27 | public $fieldsVisible = [ 28 | 'uuid' => 'id', 29 | 'users_uuid' => 'user_id', 30 | ]; 31 | 32 | /** 33 | * Fields that are editable to clients, boolean or string of visible field name 34 | * 35 | * @var array $fieldsEditable 36 | */ 37 | protected $fieldsEditable = [ 38 | 'value', 39 | ]; 40 | 41 | /** 42 | * Key visibility to clients, boolean or string of visible field name 43 | * 44 | * @var array $apiFields 45 | * @link https://github.com/Wixel/GUMP 46 | */ 47 | public $keysVisible = [ 48 | '', 49 | ]; 50 | 51 | /** 52 | * Filter rules for fields 53 | * 54 | * @var array $filterRules 55 | * @link https://github.com/Wixel/GUMP 56 | */ 57 | public $filterRules = [ 58 | 'uuid' => 'trim|sanitize_string|lower', 59 | 'users_uuid' => 'trim|sanitize_string|lower', 60 | 'key' => 'trim|sanitize_string|slug', 61 | 'value' => 'trim', 62 | 'type' => 'trim|sanitize_string|lower', 63 | ]; 64 | 65 | /** 66 | * Validation rules for fields 67 | * 68 | * @var array $validationRules 69 | * @link https://github.com/Wixel/GUMP 70 | */ 71 | public $validationRules = [ 72 | 'uuid' => 'alpha_dash', 73 | 'users_uuid' => 'alpha_dash', 74 | ]; 75 | } 76 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Models/Assets.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class Assets extends DB 15 | { 16 | 17 | /** 18 | * @var \FFCMS\Mappers\Assets mapper for asset 19 | */ 20 | public $mapper; 21 | 22 | /** 23 | * initialize with array of params, 'db' and 'logger' can be injected 24 | * 25 | * @param null|\Log $logger 26 | * @param null|\DB\SQL $db 27 | */ 28 | public function __construct(array $params = [], \Log $logger = null, \DB\SQL $db = null) 29 | { 30 | parent::__construct($params, $logger, $db); 31 | 32 | $this->mapper = new Mappers\Assets; 33 | } 34 | 35 | /** 36 | * Get the associated asset mapper 37 | * 38 | * @return \FFCMS\Mappers\Assets 39 | */ 40 | public function &getMapper() 41 | { 42 | return $this->mapper; 43 | } 44 | 45 | /** 46 | * Return the URL path to the asset 47 | * 48 | * @param string $assetPath the path in assets, must prefix slash, no trailing slash 49 | * @return string return the url path or false if not exists 50 | */ 51 | public function assetUrlPath($assetPath): string 52 | { 53 | $f3 = \Base::instance(); 54 | return $f3->get('assets.url') . $assetPath; 55 | } 56 | 57 | /** 58 | * Create if needed, and return the dir to the asset path 59 | * 60 | * @param string $assetPath 61 | * @return string string $assetPath the path in assets 62 | */ 63 | public function assetDirPath($assetPath): string 64 | { 65 | $f3 = \Base::instance(); 66 | $dir = $f3->get('assets.dir') . $assetPath; 67 | if (!file_exists($dir)) { 68 | mkdir($dir, 0777, true); 69 | } 70 | return $dir . '/'; 71 | } 72 | 73 | /** 74 | * Create if needed, and return the path to the asset file path 75 | * 76 | * @param string $dirPath dir for the $filename 77 | * @param string $filename filename for asset 78 | * @return string $path to the asset 79 | */ 80 | public function assetFilePath($dirPath, $filename): string 81 | { 82 | return $this->assetDirPath($dirPath) . $filename; 83 | } 84 | 85 | /** 86 | * Return the URL path to the asset if exists or false 87 | * 88 | * @param string $dirPath dir for the $filename 89 | * @return boolean $path to the asset 90 | * @return boolean true if the asset exists 91 | */ 92 | public function assetExists($dirPath, $filename): boolean 93 | { 94 | return file_exists($this->assetFilePath($dirPath, $filename)); 95 | } 96 | 97 | /** 98 | * Return the URL path to the asset if exists or false 99 | * 100 | * @param string $dirPath dir for the $filename 101 | * @return false|string return the url path or false if not exists 102 | */ 103 | public function assetUrl($dirPath, $filename) 104 | { 105 | $url = $this->assetExists($dirPath, $filename) ? $this->assetUrlPath($dirPath . '/' . $filename) : false; 106 | if (empty($url)) { 107 | return false; 108 | } 109 | return $url . '?' . filesize($this->assetFilePath($dirPath, $filename)); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Models/Base.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | abstract class Base extends \Prefab 15 | { 16 | use Traits\Validation; 17 | 18 | /** 19 | * initialize with array of params, 'db' and 'logger' can be injected 20 | * 21 | * @param array $params 22 | * @param null|\Log $logger 23 | */ 24 | public function __construct(array $params = [], \Log $logger = null) 25 | { 26 | if (is_object($logger)) { 27 | \Registry::set('logger', $logger); 28 | } 29 | 30 | foreach ($params as $k => $v) { 31 | $this->$k = $v; 32 | } 33 | 34 | // save default validation rules and filter rules in-case we add rules 35 | $this->validationRulesDefault = $this->validationRules; 36 | $this->filterRulesDefault = $this->filterRules; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Models/ConfigData.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class ConfigData extends DB 15 | { 16 | /** 17 | * @var \FFCMS\Mappers\ConfigData 18 | */ 19 | public $mapper; 20 | 21 | /** 22 | * initialize with array of params, 'db' and 'logger' can be injected 23 | * 24 | * @param null|\Log $logger 25 | * @param null|\DB\SQL $db 26 | */ 27 | public function __construct(array $params = [], \Log $logger = null, \DB\SQL $db = null) 28 | { 29 | parent::__construct($params, $logger, $db); 30 | 31 | $this->mapper = new Mappers\ConfigData; 32 | } 33 | 34 | /** 35 | * get config_data table values for given keys 36 | * 37 | * @param array $keys config_data keys to load 38 | */ 39 | public function getValues(array $keys = []): array 40 | { 41 | $m = $this->getMapper(); 42 | $data = []; 43 | 44 | // tidy up keys for query 45 | $keys = array_unique($keys); 46 | ksort($keys); 47 | $keys = array_map(function($key) use ($m) { 48 | return $m->quote($key); 49 | }, $keys); 50 | 51 | // load keys query 52 | $sql = sprintf("%s IN (%s)", $m->quotekey('key'), join(',', $keys)); 53 | 54 | // execute query, count results 55 | $results = $m->load($sql); 56 | $count = count($results); 57 | if ($count == 0) { 58 | return $data; 59 | } 60 | 61 | // get values and return them 62 | do { 63 | $data[$m->key]= $m->value; 64 | } 65 | while ($m->skip()); 66 | 67 | return $data; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Models/DB.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | * @see https://fatfreeframework.com/sql 14 | */ 15 | abstract class DB extends Base 16 | { 17 | /** 18 | * @var \DB\SQL database class 19 | */ 20 | public $db; 21 | 22 | /** 23 | * @var string table in the db 24 | */ 25 | public $table; 26 | 27 | /** 28 | * @var string class name 29 | */ 30 | public $mapperClass; 31 | 32 | /** 33 | * @var \FFCMS\Mappers\Mapper for class 34 | */ 35 | public $mapper; 36 | 37 | 38 | /** 39 | * initialize with array of params, 'db' and 'logger' can be injected 40 | * 41 | * @param null|\Log $logger 42 | * @param null|\DB\SQL $db 43 | */ 44 | public function __construct(array $params = [], \Log $logger = null, \DB\SQL $db = null) 45 | { 46 | $f3 = \Base::instance(); 47 | 48 | if (is_object($logger)) { 49 | \Registry::set('logger', $logger); 50 | } 51 | 52 | if (is_object($db)) { 53 | \Registry::set('db', $db); 54 | } 55 | $this->db = \Registry::get('db'); 56 | 57 | // guess the table name from the class name if not specified as a class member 58 | $class = strrchr(get_class($this), '\\'); 59 | $class = \UTF::instance()->substr($class,1); 60 | if (empty($this->table)) { 61 | $table = $f3->snakecase($class); 62 | } else { 63 | $table = $this->table; 64 | } 65 | $this->table = $table; 66 | 67 | $mapperClass = "\FFCMS\Mappers\\" . $class; 68 | if (class_exists($mapperClass)) { 69 | $this->mapper = new $mapperClass; 70 | $this->mapperClass = $mapperClass; 71 | } 72 | 73 | foreach ($params as $k => $v) { 74 | $this->$k = $v; 75 | } 76 | } 77 | 78 | /** 79 | * Get the associated mapper for the table 80 | * @return \FFCMS\Mappers\Mapper $this->mapper 81 | */ 82 | public function &getMapper() 83 | { 84 | return $this->mapper; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Models/OAuth2.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright (c) Copyright 2016 Vijay Mahrra 12 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 13 | */ 14 | class OAuth2 extends DB 15 | { 16 | /** 17 | * @var \FFCMS\Mappers\Oauth2Apps mapper for apps 18 | */ 19 | protected $appsMapper; 20 | 21 | /** 22 | * @var \FFCMS\Mappers\Oauth2Tokens data mapper for apps tokens 23 | */ 24 | protected $tokensMapper; 25 | 26 | 27 | /** 28 | * initialize with array of params, 'db' and 'logger' can be injected 29 | * 30 | * @param null|\Log $logger 31 | * @param null|\DB\SQL $db 32 | */ 33 | public function __construct(array $params = [], \Log $logger = null, \DB\SQL $db = null) 34 | { 35 | parent::__construct($params, $logger, $db); 36 | 37 | $this->appsMapper = new Mappers\OAuth2Apps; 38 | $this->tokensMapper = new Mappers\OAuth2Tokens; 39 | } 40 | 41 | 42 | /** 43 | * Get the associated apps mapper 44 | * 45 | * @return \FFCMS\Mappers\OAuth2Apps 46 | */ 47 | public function &getAppsMapper() 48 | { 49 | return $this->appsMapper; 50 | } 51 | 52 | 53 | /** 54 | * Get the associated app tokens mapper 55 | * 56 | * @return \FFCMS\Mappers\OAuth2Tokens 57 | */ 58 | public function &getTokensMapper() 59 | { 60 | return $this->tokensMapper; 61 | } 62 | 63 | 64 | /** 65 | * Get users list of apps 66 | * 67 | * @param string $uuid the user uuid 68 | * @return \DB\SQL\Mapper[] $data new user data 69 | */ 70 | public function getUserApps($uuid) 71 | { 72 | $appsMapper = $this->getAppsMapper(); 73 | return $appsMapper->find(['users_uuid = ?', $uuid]); 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Setup.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright (c) Copyright 2016 Vijay Mahrra 10 | * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) 11 | */ 12 | class Setup 13 | { 14 | /** 15 | * setup database 16 | * 17 | * @param \Dice\Dice dependency injector 18 | * @return void 19 | */ 20 | public static function database(\Dice\Dice &$dice) 21 | { 22 | $f3 = \Base::instance(); 23 | $cache = \Cache::instance(); 24 | // cli mode will not use cache on cli and will check db every time if in dev mode 25 | if ($f3->get('db.create') && (!$cache->exists('tables', $tables) || $f3->get('CLI') || 'dev' == $f3->get('app.env'))) { 26 | $db = $dice->create('DB\\SQL'); 27 | $tables = $db->exec('SHOW TABLES'); 28 | if (empty($tables)) { 29 | $sql = $f3->get('HOMEDIR') . '/data/db/sql/create.sql'; 30 | $db->exec(file_get_contents($sql)); 31 | $tables = $db->exec('SHOW TABLES'); 32 | 33 | // create initial admin user 34 | $usersModel = $dice->create('FFCMS\\Models\\Users'); 35 | $usersMapper = $usersModel->newUserTemplate(); 36 | $usersMapper->email = $f3->get('email.from'); 37 | $usersMapper->firstname = 'Root'; 38 | $usersMapper->lastname = 'Beer'; 39 | $usersMapper->status = 'confirmed'; 40 | $usersMapper->scopes = 'user,api,admin,root'; 41 | $usersMapper->password_question = '1+1=?'; 42 | $usersMapper->password_answer = '2'; 43 | $usersMapper->password = 'admin'; 44 | $usersModel->register(); 45 | 46 | // create initial admin api access 47 | $appsMapper = $dice->create('FFCMS\\Mappers\\OAuth2Apps'); 48 | $appsMapper->name = 'Admin App'; 49 | $appsMapper->scope = 'read,write'; 50 | $appsMapper->status = 'approved'; 51 | $appsMapper->created = $usersMapper->created; 52 | $appsMapper->users_uuid = $usersMapper->uuid; 53 | $appsMapper->client_id = $appsMapper->setUUID('client_id'); 54 | $appsMapper->client_secret = $appsMapper->setUUID('client_secret'); 55 | $appsMapper->save(); 56 | } 57 | $cache->set('tables', $tables, 600); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Traits/Notification.php: -------------------------------------------------------------------------------- 1 | [messages] OR message string 14 | * @param string|null $type type of messages (success, error, warning, info) OR null if multiple $data 15 | * @return bool success 16 | */ 17 | public function notify($data, $type = null) 18 | { 19 | if (is_array($data)) { 20 | return \FFMVC\Helpers\Notifications::instance()->addMultiple($data); 21 | } else { 22 | return \FFMVC\Helpers\Notifications::instance()->add($data, $type); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Traits/SecurityController.php: -------------------------------------------------------------------------------- 1 | get('security.csrf'))) { 42 | return false; 43 | } 44 | 45 | // security check 46 | // true if page iS GET, OR page is POST and REQUEST csrf matched session 47 | $verb = $f3->get('VERB'); 48 | $passed = ('GET' == $verb) || 49 | ('POST' == $verb && $f3->get('REQUEST.csrf') === $f3->get('SESSION.csrf')); 50 | 51 | // redirect if not POST or csrf present 52 | if (!$passed) { 53 | $f3->clear('SESSION.csrf'); 54 | $url = $this->url($url, $params); 55 | return $f3->reroute($url); 56 | } 57 | 58 | // if GET/POST generate a new csrf token 59 | $session = \Registry::get('session'); 60 | $f3->csrf = $session->csrf(); 61 | $f3->copy('csrf', 'SESSION.csrf'); 62 | 63 | return true; 64 | } 65 | 66 | 67 | /** 68 | * Check ip-address is blacklisted, halt, if-so 69 | * 70 | * @return bool 71 | */ 72 | public function dnsbl(): bool 73 | { 74 | $f3 = \Base::instance(); 75 | $cache = \Cache::instance(); 76 | 77 | $ip = $f3->get('IP'); 78 | $f3->set('DNSBL', $f3->get('security.dnsbl')); 79 | if (!$cache->exists($ip, $isBlacklisted)) { 80 | $isBlacklisted = $f3->blacklisted($ip); 81 | $cache->set($ip, $isBlacklisted, $f3->get('ttl.blacklist')); 82 | } 83 | if (false !== $isBlacklisted) { 84 | printf(_("Your ip-address '%s' is blacklisted!"), $ip); 85 | $f3->halt(); 86 | } 87 | return true; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /app/lib/FFCMS/Traits/UrlHelper.php: -------------------------------------------------------------------------------- 1 | internal($url, $params); 21 | } 22 | 23 | 24 | /** 25 | * Create an external URL 26 | * 27 | * @param string $url 28 | * @param array $params 29 | */ 30 | public function xurl(string $url, array $params = [], bool $https = true): string 31 | { 32 | return \FFMVC\Helpers\Url::instance()->external($url, $params, $https); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/audit/view.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | $data = $f3->get('data'); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

14 | 15 | 16 | 17 | 18 | $value): ?> 19 | 20 | 21 | 22 | 23 | 24 | 25 | $value): ?> 26 | 27 | 28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 | render('cms/footer-menu.phtml'); ?> 36 | render('cms/footer.phtml'); ?> 37 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/config.phtml: -------------------------------------------------------------------------------- 1 | get('user'); 4 | $title = 'Config'; 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | render('cms/footer-menu.phtml'); ?> 17 | render('cms/footer.phtml'); ?> 18 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/config/add.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 7 | ?> 8 | render('cms/header.phtml'); ?> 9 | render('cms/header-menu.phtml'); ?> 10 | render('cms/notifications.phtml'); ?> 11 | 12 |
13 | 14 |

15 | 16 |
17 | 18 | 19 | 20 |
21 | 22 | Add 23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 |
33 | 34 |
35 | 43 |
44 | 45 |
46 | 47 |

Note: You must enter the value on the edit page afterwards.

48 |
49 | 50 |
51 | 52 |
53 | 54 |
55 | 56 | 57 | render('cms/footer-menu.phtml'); ?> 58 | render('cms/footer.phtml'); ?> 59 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/index.phtml: -------------------------------------------------------------------------------- 1 | get('user'); 4 | $title = 'CMS Admin'; 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
    15 |
  • phpinfo
  • 16 |
  • Audit Trail - Audit history of changes to the database
  • 17 |
  • Config - Website configuration data/options
  • 18 |
  • Reports - SQL reports, exportable as CSV
  • 19 |
  • Users - Al website and cms users
  • 20 |
  • Users Data - Supplementary data of users
  • 21 |
  • Apps - Registered OAuth2 API apps of users
  • 22 |
  • Tokens - Tokens granted to registered, approved apps
  • 23 |
  • Pages - Website pages
  • 24 |
25 | 26 |

Documentation

27 | 28 |
    29 | get('HOMEDIR') . '/docs/*.md'); ?> 30 | 31 |
  • 32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | render('cms/footer-menu.phtml'); ?> 40 | render('cms/footer.phtml'); ?> 41 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/oauth2.phtml: -------------------------------------------------------------------------------- 1 | get('user'); 4 | $title = 'OAuth2'; 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | render('cms/footer-menu.phtml'); ?> 17 | render('cms/footer.phtml'); ?> 18 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/reports/add.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 | New 21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 | 44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 | 63 | render('cms/footer-menu.phtml'); ?> 64 | render('cms/footer.phtml'); ?> 65 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/reports/edit.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 | Edit 21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 | 44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 | 63 | render('cms/footer-menu.phtml'); ?> 64 | render('cms/footer.phtml'); ?> 65 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/tokens/edit.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 | 21 | 22 |
23 | 24 | Token 25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 |
35 | 36 |
37 | 38 |
39 | 40 |
41 | 42 |
43 |
44 | 45 |
46 | 47 |
48 | 49 | render('cms/footer-menu.phtml'); ?> 50 | render('cms/footer.phtml'); ?> 51 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/usersdata/add.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 | Add 21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 | 50 |
51 | 52 | 53 | render('cms/footer-menu.phtml'); ?> 54 | render('cms/footer.phtml'); ?> 55 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/admin/usersdata/edit.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 | Edit 21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | get('form.type')): 29 | case 'url': ?> 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 |
53 | 54 | 55 |
56 | 57 |
58 | 59 |
60 | 61 |
62 | 63 |
64 | 65 |
66 | 67 | 68 | render('cms/footer-menu.phtml'); ?> 69 | render('cms/footer.phtml'); ?> 70 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/footer-menu.phtml: -------------------------------------------------------------------------------- 1 | get('user'); 4 | $scopes = $f3->get('userScopes'); 5 | ?> 6 | 52 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/footer.phtml: -------------------------------------------------------------------------------- 1 | get('analytics'); 4 | $analytics['enabled'] = $analytics['enabled'] && 'production' == $f3->get('app.env'); 5 | ?> 6 | 7 | 16 | 17 | 18 | get('js.load'); if (is_array($js)): foreach ($js as $script): ?> 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/header.phtml: -------------------------------------------------------------------------------- 1 | get('page'); 4 | if (is_array($page)) { 5 | extract($page); 6 | } 7 | ?> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <?=$title ?> 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | */ ?> 24 | 25 | 26 | 27 | 28 | get('css.load'); if (is_array($css)): foreach ($css as $k => $script): ?> 29 | > 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/notifications.phtml: -------------------------------------------------------------------------------- 1 | 'green lighten-5', 8 | 'error' => 'white', 9 | 'warning' => 'white', 10 | 'info' => 'white', 11 | 'debug' => 'white' 12 | ]; 13 | $icons = [ 14 | 'success' => 'done', 15 | 'error' => 'error', 16 | 'warning' => 'report_problem', 17 | 'info' => 'info_outline', 18 | 'debug' => 'new_releases' 19 | ]; 20 | echo '
'; 21 | foreach ($notifications as $type => $msgs): 22 | $icon = $icons[$type]; 23 | $colour = $colours[$type]; 24 | foreach ($msgs as $notification): 25 | echo '
' . $icon . ' ' . $notification . '
'; 26 | endforeach; 27 | endforeach; 28 | echo '
'; 29 | endif; 30 | ?> 31 | -------------------------------------------------------------------------------- /app/templates/en/cms/cms/paginator.phtml: -------------------------------------------------------------------------------- 1 | ref('results'); 4 | $p =& $results['pagination']; 5 | ?> 6 | $p['pages']) { 30 | $endNumber = $p['pages']; 31 | } 32 | 33 | // jump forward 34 | $jumpForward = $endNumber + 3; 35 | if ($jumpForward > $p['pages']) { 36 | $jumpForward = null; 37 | } 38 | $p['url_jump_forward'] = empty($jumpForward) ? '' : $p['url_base'] . '&page=' . $jumpForward; 39 | ?> 40 |
41 |
42 | 43 | 56 | 57 |
58 |
59 | -------------------------------------------------------------------------------- /app/templates/en/skin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/app/templates/en/skin/.gitkeep -------------------------------------------------------------------------------- /app/templates/en/website/apps/docs.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |

Your API Credentials

15 |

Client Id: get('user.email') ?>

16 |

Access Token: get('user.access_token') ?>

17 |

Refresh Token: get('user.refresh_token') ?>

18 | 19 | get('html') ?> 20 | 21 |
22 | 23 | render('cms/footer-menu.phtml'); ?> 24 | render('cms/footer.phtml'); ?> 25 | -------------------------------------------------------------------------------- /app/templates/en/website/email/confirm_email.md: -------------------------------------------------------------------------------- 1 | get('templateData'); 3 | $link = $d['url'] . '?code=' . $d['code']; 4 | ?> 5 | Dear , 6 | 7 | You recently registered or updated your account email address with us. 8 | 9 | Please click on the link below to confirm your email address: 10 | 11 | * []() 12 | 13 | 14 | Regards, 15 | 16 | get('email.from_name') ?> 17 | 18 | [get('email.from') ?>](mailto:get('email.from') ?>) 19 | -------------------------------------------------------------------------------- /app/templates/en/website/email/forgot_password.md: -------------------------------------------------------------------------------- 1 | get('templateData'); 3 | $link = $d['url'] . '?code=' . $d['code']; 4 | ?> 5 | Dear , 6 | 7 | A password reset was requested from our website. 8 | 9 | Please click on the link below to reset your password: 10 | 11 | * []() 12 | 13 | Or enter the code **``** at: 14 | 15 | * []() 16 | 17 | 18 | Regards, 19 | 20 | get('email.from_name') ?> 21 | 22 | [get('email.from') ?>](mailto:get('email.from') ?>) 23 | -------------------------------------------------------------------------------- /app/templates/en/website/error/404.phtml: -------------------------------------------------------------------------------- 1 | get('ERROR'); 4 | $title = 'Error: ' . $e['code']; 5 | $f3->set('title', $title); 6 | $debug = $f3->get('DEBUG'); 7 | ?> 8 | render('cms/header.phtml'); ?> 9 | 10 | 11 |
12 | 13 |

Error:

14 | 15 |


16 | 17 | get('app.env') !== 'production'): ?> 18 | 19 | 0): ?> 20 | 21 |

Error Context

22 |
23 |             
24 |             
25 | 26 | 27 | 28 | 1): ?> 29 | 30 |

Error Trace

31 |
32 |                 trace(null, false)); ?>
33 |             
34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | render('cms/footer.phtml'); ?> 42 | -------------------------------------------------------------------------------- /app/templates/en/website/error/debug.phtml: -------------------------------------------------------------------------------- 1 | get('ERROR'); 4 | $title = 'Error: ' . $e['code']; 5 | $f3->set('title', $title); 6 | $debug = $f3->get('DEBUG'); 7 | ?> 8 | render('cms/header.phtml'); ?> 9 | 10 | 11 |
12 | 13 |

14 | 15 |

16 |
17 | We're sorry but an error occurred. Our best muppets are on the case. 18 |

19 | 20 | get('app.env') !== 'production'): ?> 21 | 0): ?> 22 | 23 |

Error Context

24 |
25 |             
26 |             
27 | 28 | 29 | 30 | 1): ?> 31 | 32 |

Error Trace

33 |
34 |                 trace(null, false)); ?>
35 |             
36 | 37 | 38 | 39 | 2): ?> 40 | 41 |

F3 Hive

42 |
43 |                 dump($f3->hive()) ?>
44 |             
45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | render('cms/footer.phtml'); ?> 53 | -------------------------------------------------------------------------------- /app/templates/en/website/error/error.phtml: -------------------------------------------------------------------------------- 1 | get('ERROR'); 4 | $title = 'Error: ' . $e['code']; 5 | $f3->set('title', $title); 6 | $debug = $f3->get('DEBUG'); 7 | ?> 8 | render('cms/header.phtml'); ?> 9 | 10 | 11 |
12 | 13 |

14 | 15 |

16 |
17 | We're sorry but an error occurred. 18 |

19 | 20 | get('app.env') !== 'production'): ?> 21 | 0): ?> 22 | 23 |

Error Context

24 |
25 |             
26 |             
27 | 28 | 29 | 30 | 1): ?> 31 | 32 |

Error Trace

33 |
34 |                 trace(null, false)); ?>
35 |             
36 | 37 | 38 | 39 | 40 |
41 | 42 | render('cms/footer.phtml'); ?> 43 | -------------------------------------------------------------------------------- /app/templates/en/website/forgot_password/forgot_password_step1.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 |
18 |
19 | 20 |
21 | 22 | vpn_key 23 | 24 |
25 | mail 26 | 27 | 28 |
29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 |
41 | 42 | render('cms/footer-menu.phtml'); ?> 43 | render('cms/footer.phtml'); ?> 44 | -------------------------------------------------------------------------------- /app/templates/en/website/forgot_password/forgot_password_step2.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 |
18 | 19 | mail 20 | 21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 |
29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 | render('cms/footer-menu.phtml'); ?> 37 | render('cms/footer.phtml'); ?> 38 | -------------------------------------------------------------------------------- /app/templates/en/website/forgot_password/forgot_password_step3.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 | 13 |

14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | lock 24 | 25 |
26 | 27 | 28 |
29 |
30 | vpn_key 31 | 32 | 33 |
34 |
35 | vpn_key 36 | 37 | 38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 | 50 | render('cms/footer-menu.phtml'); ?> 51 | render('cms/footer.phtml'); ?> 52 | -------------------------------------------------------------------------------- /app/templates/en/website/index/blank.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 4 | ?> 5 | render('cms/header.phtml'); ?> 6 | render('cms/header-menu.phtml'); ?> 7 | render('cms/notifications.phtml'); ?> 8 | 9 |
10 | 11 |

12 | 13 |
14 | 15 | render('cms/footer-menu.phtml'); ?> 16 | render('cms/footer.phtml'); ?> 17 | -------------------------------------------------------------------------------- /app/templates/en/website/index/index.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 4 | ?> 5 | render('cms/header.phtml'); ?> 6 | render('cms/header-menu.phtml'); ?> 7 | render('cms/notifications.phtml'); ?> 8 | 9 |
10 | 11 |

f3-cms

12 | 13 |
14 | get('uuid'))): ?> 15 | Login 16 | Register 17 | 18 |

This project is by Vijay Mahrra and it is built on, and serves as, an example of the Fat-Free Framework

19 |
20 | 21 |
22 | 23 | render('cms/footer-menu.phtml'); ?> 24 | render('cms/footer.phtml'); ?> 25 | -------------------------------------------------------------------------------- /app/templates/en/website/markdown-template.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 4 | ?> 5 | render('cms/header.phtml'); ?> 6 | render('cms/header-menu.phtml'); ?> 7 | render('cms/notifications.phtml'); ?> 8 | 9 |
10 | 11 |

12 | 13 | get('html') ?> 14 | 15 |
16 | 17 | render('cms/footer-menu.phtml'); ?> 18 | render('cms/footer.phtml'); ?> 19 | -------------------------------------------------------------------------------- /app/templates/en/website/oauth2/authenticate.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | $user = $f3->get('user'); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

14 | 15 | 16 | get('errors')): ?> 17 | 18 |

There was a problem with the app that sent you here.

19 | 20 | 21 | 22 |

23 | , 24 | a third party app would like to: 25 |

26 |
    27 | get('permissions') as $permission): ?> 28 |
  • 29 | 30 |
31 |

32 | By clicking "Allow", you allow this app to use your information in accordance with their respective terms of service and privacy policies. You can change this and other Account Permissions at any time. 33 |

34 |
35 | 36 | 37 | 38 |
39 | 40 | Deny 41 |
42 | 43 |
44 | 45 | 46 | 47 |
48 | 49 | render('cms/footer-menu.phtml'); ?> 50 | render('cms/footer.phtml'); ?> 51 | -------------------------------------------------------------------------------- /app/templates/en/website/oauth2/callback.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | $user = $f3->get('user'); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

14 | 15 | get('retrieveTokenURL')): ?> 16 |

17 | Retrieve token URL: get('retrieveTokenURL') ?> 18 | Normally you will want to do this using basic authentication rather than passing in the query string! 19 |

20 | 21 | 22 |

Request

23 |
24 |     get('form')) ?>
25 |     
26 | 27 |
28 | 29 | render('cms/footer-menu.phtml'); ?> 30 | render('cms/footer.phtml'); ?> 31 | -------------------------------------------------------------------------------- /app/templates/en/website/oauth2/confirm.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | $user = $f3->get('user'); 6 | $returnUrl = $f3->get('returnUrl'); 7 | ?> 8 | render('cms/header.phtml'); ?> 9 | render('cms/header-menu.phtml'); ?> 10 | render('cms/notifications.phtml'); ?> 11 | 12 |
13 | 14 |

15 | 16 | 17 |

You have allowed access to the app.

18 | Return to the app. 19 | 20 |

Unable to proceed.

21 | 22 | 23 |
24 | 25 | render('cms/footer-menu.phtml'); ?> 26 | render('cms/footer.phtml'); ?> 27 | -------------------------------------------------------------------------------- /app/templates/en/website/oauth2/deny.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | $user = $f3->get('user'); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

14 | 15 |

You have denied access to the app.

16 | 17 | Return to the app. 18 | 19 |
20 | 21 | render('cms/footer-menu.phtml'); ?> 22 | render('cms/footer.phtml'); ?> 23 | -------------------------------------------------------------------------------- /app/templates/en/website/pages/contact.phtml: -------------------------------------------------------------------------------- 1 | get('pagesMapper'); 4 | $f3->set('page', $p->cast()); 5 | extract($p->cast()); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

convert($title) ?>

14 | 15 | Embed a map. 16 | 17 |
18 | 19 |
20 | 21 | convert($body) ?> 22 | 23 |
24 | 25 | render('cms/footer-menu.phtml'); ?> 26 | render('cms/footer.phtml'); ?> 27 | -------------------------------------------------------------------------------- /app/templates/en/website/pages/page.phtml: -------------------------------------------------------------------------------- 1 | get('pagesMapper'); 4 | $f3->set('page', $p->cast()); 5 | extract($p->cast()); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

convert($title) ?>

14 | 15 | convert($body) ?> 16 | 17 |
18 | 19 | render('cms/footer-menu.phtml'); ?> 20 | render('cms/footer.phtml'); ?> 21 | -------------------------------------------------------------------------------- /app/templates/en/website/user/index.phtml: -------------------------------------------------------------------------------- 1 | get('user'); 4 | $title = 'Hello ' . $user['firstname'] . '!'; 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 | 19 | 20 |
21 | 22 | render('cms/footer-menu.phtml'); ?> 23 | render('cms/footer.phtml'); ?> 24 | -------------------------------------------------------------------------------- /app/templates/en/website/user/login.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | 6 | $url = \FFMVC\Helpers\Url::internal('@login', 7 | [ 8 | 'redirect_uri' => $f3->get('form.redirect_uri') 9 | ]); 10 | ?> 11 | render('cms/header.phtml'); ?> 12 | render('cms/header-menu.phtml'); ?> 13 | render('cms/notifications.phtml'); ?> 14 | 15 |
16 | 17 |

18 | 19 |
20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | 28 |
29 | 30 | account_circle 31 | 32 |
33 | mail 34 | 35 | 36 |
37 | 38 |
39 | vpn_key 40 | 41 | 42 |
43 | 44 |
45 |
46 | 47 |
48 |
49 | Forgot Password? 50 |
Register 51 |
52 |
53 | 54 | 55 |
56 | 57 |
58 |
59 | 60 |
61 | 62 |
63 | 64 | 65 | render('cms/footer-menu.phtml'); ?> 66 | render('cms/footer.phtml'); ?> 67 | -------------------------------------------------------------------------------- /app/templates/en/website/user/profile.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | $user = $f3->get('usersMapper'); 6 | ?> 7 | render('cms/header.phtml'); ?> 8 | render('cms/header-menu.phtml'); ?> 9 | render('cms/notifications.phtml'); ?> 10 | 11 |
12 | 13 |

14 | 15 |

This is your public profile data.

16 | 17 |
18 | 19 | 20 |
21 | 22 | perm_identity 23 | 24 |
25 | 26 |
27 | profileImageExists()): ?> 28 | profileImageUrlDynamic(['height' => 150])): ?> 29 | 30 | 31 | 32 | 33 |

Profile Image (max size 4MB)

34 |
35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 |
43 |
44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 |
53 |
54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 | 69 | render('cms/footer-menu.phtml'); ?> 70 | render('cms/footer.phtml'); ?> 71 | 72 | 87 | -------------------------------------------------------------------------------- /app/templates/en/website/user/register.phtml: -------------------------------------------------------------------------------- 1 | set('title', $title); 5 | ?> 6 | render('cms/header.phtml'); ?> 7 | render('cms/header-menu.phtml'); ?> 8 | render('cms/notifications.phtml'); ?> 9 | 10 |
11 | 12 |

13 | 14 |
15 | 16 | 17 |
18 | 19 | lock 20 | 21 |
22 | mail 23 | 24 | 25 |
26 |
27 | vpn_key 28 | 29 | 30 |
31 |
32 | vpn_key 33 | 34 | 35 |
36 | 37 |
38 | 39 |
40 | 41 | account_circle 42 | 43 |
44 | 45 | 46 |
47 |
48 | 49 | 50 |
51 |
52 | 53 | 54 |
55 |
56 | 57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 |
66 | 67 |
68 | 69 | 70 | render('cms/footer-menu.phtml'); ?> 71 | render('cms/footer.phtml'); ?> 72 | -------------------------------------------------------------------------------- /bin/cli.php: -------------------------------------------------------------------------------- 1 | ../app/lib/FFCMS/CLI.php -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vijinho/f3-cms", 3 | "description": "My Fat-Free Framework skeleton mvc boilerplate application", 4 | "keywords": ["php", "php framework", "micro framework", "php micro framework", "microframework", "fat-free framework", "fat-free", "skeleton", "skeleton app", "skeleton application", "mvc"], 5 | "homepage": "https://github.com/vijinho/f3-cms", 6 | 7 | "license": "GPL-3.0", 8 | "type": "application", 9 | "authors": [ 10 | { 11 | "name": "Vijay Mahrra", 12 | "email": "vijay@yoyo.org", 13 | "homepage": "http://www.urunu.com", 14 | "role": "Developer" 15 | } 16 | ], 17 | "config": { 18 | "vendor-dir": "lib" 19 | }, 20 | "autoload": { 21 | "classmap": ["app/lib", "lib"], 22 | "exclude-from-classmap": [ 23 | "lib/bcosca/fatfree-core/smtp.php", "lib/bcosca/fatfree-core/./smtp.php" 24 | ]}, 25 | "require": { 26 | "php": ">=5.6.0", 27 | "bcosca/fatfree-core": "3.6.1", 28 | "level-2/dice": "dev-master", 29 | "filp/whoops": "dev-master", 30 | "wixel/gump": "dev-master", 31 | "league/climate": "dev-master", 32 | "phpmailer/phpmailer": "dev-master", 33 | "scriptfusion/retry": "dev-master", 34 | "robmorgan/phinx": "dev-master", 35 | "fzaninotto/faker": "dev-master", 36 | "miljar/php-exif": "dev-master", 37 | "vijinho/ffmvc": "dev-dev-master", 38 | "vijinho/enums": "dev-dev-master" 39 | }, 40 | "suggest": { 41 | "php": ">=7.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /data/db/migrations/20160713214419_users.php: -------------------------------------------------------------------------------- 1 | table('users'); 13 | $users->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36]) 14 | ->addColumn('password', 'string', ['comment' => 'Password', 'limit' => 16]) 15 | ->addColumn('email', 'string', ['comment' => 'Email', 'limit' => 255]) 16 | ->addColumn('firstname', 'string', ['comment' => 'First Name(s)', 'limit' => 128]) 17 | ->addColumn('lastname', 'string', ['comment' => 'Last Name(s)', 'limit' => 128]) 18 | ->addColumn('scopes', 'string', ['comment' => 'Account Scopes', 'limit' => 64, 'default' => 'user']) 19 | ->addColumn('status', 'string', ['comment' => 'Account Status', 'limit' => 32, 'default' => 'NEW']) 20 | ->addColumn('password_question', 'string', ['comment' => 'Password Hint Question', 'limit' => 255]) 21 | ->addColumn('password_answer', 'string', ['comment' => 'Password Hint Answer', 'limit' => 255]) 22 | ->addColumn('created', 'datetime', ['comment' => 'Created']) 23 | ->addColumn('login_count', 'integer', ['comment' => 'Login Count', 'default' => 0, 'signed' => 0]) 24 | ->addColumn('login_last', 'datetime', ['comment' => 'Last Login', 'null' => true]) 25 | ->addIndex(['uuid'], ['unique' => true]) 26 | ->addIndex(['email'], ['unique' => true]) 27 | ->save(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /data/db/migrations/20160714152505_users_data.php: -------------------------------------------------------------------------------- 1 | table('users_data'); 13 | $users->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36]) 14 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36]) 15 | ->addColumn('key', 'string', ['comment' => 'Key', 'limit' => 255]) 16 | ->addColumn('value', 'text', ['comment' => 'Value', 'null' => true]) 17 | ->addColumn('type', 'string', ['comment' => 'Type', 'limit' => 255]) 18 | ->addIndex(['uuid'], ['unique' => true]) 19 | ->addIndex(['users_uuid', 'key'], ['unique' => true]) 20 | ->addForeignKey('users_uuid', 'users', 'uuid', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']) 21 | ->save(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data/db/migrations/20160715174200_audit.php: -------------------------------------------------------------------------------- 1 | table('audit'); 13 | $users->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36]) 14 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36, 'null' => true]) 15 | ->addColumn('ip', 'string', ['comment' => 'IP-Address', 'limit' => 16, 'null' => true]) 16 | ->addColumn('agent', 'string', ['comment' => 'User-Agent', 'limit' => 255, 'null' => true]) 17 | ->addColumn('created', 'datetime', ['comment' => 'Created']) 18 | ->addColumn('actor', 'string', ['comment' => 'Actor', 'limit' => 128, 'null' => true]) 19 | ->addColumn('event', 'string', ['comment' => 'Event', 'limit' => 128, 'null' => true]) 20 | ->addColumn('description', 'string', ['comment' => 'Description', 'limit' => 255, 'null' => true]) 21 | ->addColumn('old', 'text', ['comment' => 'Old Value', 'null' => true]) 22 | ->addColumn('new', 'text', ['comment' => 'New Value', 'null' => true]) 23 | ->addColumn('debug', 'text', ['comment' => 'Debug Information', 'null' => true]) 24 | ->addIndex(['ip'], ['unique' => false]) 25 | ->addIndex(['event'], ['unique' => false]) 26 | ->addIndex(['users_uuid'], ['unique' => false]) 27 | ->addIndex(['uuid'], ['unique' => true]) 28 | ->save(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /data/db/migrations/20160717113500_config_data.php: -------------------------------------------------------------------------------- 1 | table('config_data'); 13 | $users->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36]) 14 | ->addColumn('key', 'string', ['comment' => 'Key', 'limit' => 255]) 15 | ->addColumn('value', 'text', ['comment' => 'Value', 'null' => true]) 16 | ->addColumn('type', 'string', ['comment' => 'Type', 'limit' => 32, 'null' => true]) 17 | ->addColumn('options', 'text', ['comment' => 'Options', 'null' => true]) 18 | ->addColumn('description', 'text', ['comment' => 'Description', 'null' => true]) 19 | ->addColumn('rank', 'integer', ['comment' => 'Rank', 'default' => 9999, 'null' => true]) 20 | ->addIndex(['rank'], ['unique' => false]) 21 | ->addIndex(['type'], ['unique' => false]) 22 | ->addIndex(['uuid'], ['unique' => true]) 23 | ->addIndex(['key'], ['unique' => true]) 24 | ->save(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /data/db/migrations/20160719215200_oauth2apps.php: -------------------------------------------------------------------------------- 1 | table('oauth2_apps'); 13 | $oauthApps->addColumn('created', 'datetime', ['comment' => 'Created']) 14 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36]) 15 | ->addColumn('client_id', 'string', ['comment' => 'Client Id', 'limit' => 36]) 16 | ->addColumn('client_secret', 'string', ['comment' => 'Client Secret', 'limit' => 36]) 17 | ->addColumn('name', 'string', ['comment' => 'Application Name', 'limit' => 255]) 18 | ->addColumn('logo_url', 'text', ['comment' => 'Logo Image URL', 'limit' => 1024, 'null' => true]) 19 | ->addColumn('description', 'text', ['comment' => 'Description', 'null' => true]) 20 | ->addColumn('scope', 'text', ['comment' => 'Allowed Scopes', 'null' => true]) 21 | ->addColumn('callback_uri', 'text', ['comment' => 'Callback URI', 'null' => true]) 22 | ->addColumn('redirect_uris', 'text', ['comment' => 'Redirect URIs', 'null' => true]) 23 | ->addColumn('status', 'string', ['comment' => 'Status', 'limit' => 16, 'default' => 'NEW']) 24 | ->addIndex(['name'], ['unique' => true]) 25 | ->addIndex(['client_id'], ['unique' => true]) 26 | ->addIndex(['client_secret'], ['unique' => true]) 27 | ->addIndex(['client_id', 'client_secret'], ['unique' => true]) 28 | ->addForeignKey('users_uuid', 'users', 'uuid', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']) 29 | ->save(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /data/db/migrations/20160719222400_oauth2tokens.php: -------------------------------------------------------------------------------- 1 | table('oauth2_tokens'); 13 | $oauthTokens->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36, 'null' => false]) 14 | ->addColumn('created', 'datetime', ['comment' => 'Created']) 15 | ->addColumn('expires', 'datetime', ['comment' => 'Expires', 'null' => true]) 16 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36]) 17 | ->addColumn('client_id', 'string', ['comment' => 'Client Id', 'limit' => 36]) 18 | ->addColumn('token', 'string', ['comment' => 'Token Value', 'limit' => 36]) 19 | ->addColumn('type', 'string', ['comment' => 'Token Type', 'limit' => 16]) 20 | ->addColumn('scope', 'text', ['comment' => 'Allowed Scopes', 'null' => true]) 21 | ->addIndex(['uuid'], ['unique' => true]) 22 | ->addIndex(['token'], ['unique' => true]) 23 | ->addIndex(['client_id', 'users_uuid', 'type'], ['unique' => true]) 24 | ->addForeignKey('client_id', 'oauth2_apps', 'client_id', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']) 25 | ->addForeignKey('users_uuid', 'users', 'uuid', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']) 26 | ->save(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /data/db/migrations/20160805134100_reports.php: -------------------------------------------------------------------------------- 1 | table('reports'); 13 | $oauthTokens->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36, 'null' => false]) 14 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36]) 15 | ->addColumn('scopes', 'string', ['comment' => 'Account Scopes', 'limit' => 64, 'default' => 'user']) 16 | ->addColumn('key', 'string', ['comment' => 'Key', 'limit' => 255]) 17 | ->addColumn('name', 'string', ['comment' => 'Name', 'limit' => 255]) 18 | ->addColumn('description', 'text', ['comment' => 'Description', 'null' => true]) 19 | ->addColumn('query', 'text', ['comment' => 'Query', 'null' => true]) 20 | ->addColumn('options', 'text', ['comment' => 'Extra Options', 'null' => true]) 21 | ->addColumn('created', 'datetime', ['comment' => 'Created']) 22 | ->addIndex(['key'], ['unique' => true]) 23 | ->addIndex(['uuid'], ['unique' => true]) 24 | ->addForeignKey('users_uuid', 'users', 'uuid', ['delete' => 'CASCADE', 'update' => 'CASCADE']) 25 | ->save(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /data/db/migrations/20160829172800_assets.php: -------------------------------------------------------------------------------- 1 | table('assets'); 13 | $assets->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36, 'null' => false]) 14 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36, 'null' => true]) 15 | ->addColumn('key', 'string', ['comment' => 'Key', 'limit' => 255, 'null' => true]) 16 | ->addColumn('groups', 'string', ['comment' => 'Groups', 'limit' => 255, 'null' => true]) 17 | ->addColumn('name', 'string', ['comment' => 'Name', 'limit' => 255, 'null' => true]) 18 | ->addColumn('description', 'text', ['comment' => 'Description', 'null' => true]) 19 | ->addColumn('filename', 'text', ['comment' => 'Filename']) 20 | ->addColumn('size', 'integer', ['comment' => 'File Size', 'default' => 0, 'null' => false]) 21 | ->addColumn('type', 'string', ['comment' => 'Mime Type', 'limit' => 255, 'null' => true]) 22 | ->addColumn('categories', 'text', ['comment' => 'Categories', 'null' => true]) 23 | ->addColumn('tags', 'text', ['comment' => 'Tags', 'null' => true]) 24 | ->addColumn('created', 'datetime', ['comment' => 'Created']) 25 | ->addColumn('updated', 'datetime', ['comment' => 'Updated', 'null' => true]) 26 | ->addColumn('url', 'text', ['comment' => 'URL', 'null' => true]) 27 | ->addColumn('metadata', 'text', ['comment' => 'Additional Metadata', 'null' => true]) 28 | ->addIndex(['users_uuid', 'key'], ['unique' => false]) 29 | ->addIndex(['type'], ['unique' => false]) 30 | ->addIndex(['users_uuid'], ['unique' => false]) 31 | ->addIndex(['uuid'], ['unique' => true]) 32 | ->save(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /data/db/migrations/20160901181900_pages.php: -------------------------------------------------------------------------------- 1 | table('pages'); 13 | $pages->addColumn('uuid', 'string', ['comment' => 'UUID', 'limit' => 36, 'null' => false]) 14 | ->addColumn('users_uuid', 'string', ['comment' => 'User UUID', 'limit' => 36, 'null' => true]) 15 | ->addColumn('key', 'string', ['comment' => 'Key', 'limit' => 255, 'null' => true]) 16 | ->addColumn('author', 'string', ['comment' => 'Author', 'limit' => 255, 'null' => true]) 17 | ->addColumn('language', 'string', ['comment' => 'Language', 'limit' => 5, 'default' => 'en', 'null' => true]) 18 | ->addColumn('status', 'string', ['comment' => 'Publish Status', 'limit' => 255, 'null' => true]) 19 | ->addColumn('slug', 'string', ['comment' => 'Slug', 'limit' => 255, 'null' => true]) 20 | ->addColumn('path', 'text', ['comment' => 'URL Path', 'null' => true]) 21 | ->addColumn('keywords', 'text', ['comment' => 'Keywords', 'null' => true]) 22 | ->addColumn('description', 'text', ['comment' => 'Description', 'null' => true]) 23 | ->addColumn('robots', 'boolean', ['comment' => 'Allow Robots?', 'default' => 1, 'null' => true]) 24 | ->addColumn('title', 'string', ['comment' => 'Title', 'limit' => 255, 'null' => true]) 25 | ->addColumn('summary', 'text', ['comment' => 'Summary', 'null' => true]) 26 | ->addColumn('body', 'text', ['comment' => 'Body Content', 'null' => true]) 27 | ->addColumn('scopes', 'string', ['comment' => 'Scopes', 'limit' => 255, 'null' => true]) 28 | ->addColumn('category', 'text', ['comment' => 'Categories', 'limit' => 255, 'null' => true]) 29 | ->addColumn('tags', 'text', ['comment' => 'Tags', 'null' => true]) 30 | ->addColumn('metadata', 'text', ['comment' => 'Additional Metadata', 'null' => true]) 31 | ->addColumn('created', 'datetime', ['comment' => 'Date Created']) 32 | ->addColumn('published', 'datetime', ['comment' => 'Date Published', 'null' => true]) 33 | ->addColumn('expires', 'datetime', ['comment' => 'Date Expires', 'null' => true]) 34 | ->addColumn('updated', 'datetime', ['comment' => 'Last Updated', 'null' => true]) 35 | ->addIndex(['slug'], ['unique' => true]) 36 | ->addIndex(['language'], ['unique' => false]) 37 | ->addIndex(['status'], ['unique' => false]) 38 | ->addIndex(['users_uuid'], ['unique' => false]) 39 | ->addIndex(['uuid'], ['unique' => true]) 40 | ->save(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /data/db/seeds/UserSeeder.php: -------------------------------------------------------------------------------- 1 | $faker->uuid, 25 | 'password' => substr(sha1($faker->password),0,15), 26 | 'email' => $faker->email, 27 | 'firstname' => $faker->firstName, 28 | 'lastname' => $faker->lastName, 29 | 'scopes' => $scopes[rand(0,4)], 30 | 'status' => $statuses[rand(0,4)], 31 | 'password_question' => $faker->sentence(10, true), 32 | 'password_answer' => $faker->sentence(3), 33 | 'created' => $faker->dateTimeBetween('-3 years', 'now')->format('Y-m-d H:i:s'), 34 | 'login_last' => $faker->dateTimeBetween('-3 years', 'now')->format('Y-m-d H:i:s'), 35 | 'login_count' => rand(1, 1000) 36 | ]; 37 | // flush data to database 38 | if (count($data) > $flush) { 39 | $this->insert('users', $data); 40 | $data = []; 41 | } 42 | } 43 | if (count($data) > $flush) { 44 | $this->insert('users', $data); 45 | $data = []; 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /data/db/sql/audit-archive.sql: -------------------------------------------------------------------------------- 1 | -- Convert audit table to table engine 'archive' 2 | ALTER TABLE audit DROP INDEX uuid; 3 | ALTER TABLE audit ENGINE = ARCHIVE; 4 | -------------------------------------------------------------------------------- /data/db/sql/phinx.sql: -------------------------------------------------------------------------------- 1 | # ************************************************************ 2 | # Sequel Pro SQL dump 3 | # Version 4541 4 | # 5 | # http://www.sequelpro.com/ 6 | # https://github.com/sequelpro/sequelpro 7 | # 8 | # Host: localhost (MySQL 5.5.42) 9 | # Database: development_db 10 | # Generation Time: 2016-08-29 16:50:54 +0000 11 | # ************************************************************ 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 19 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 20 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 21 | 22 | 23 | # Dump of table phinxlog 24 | # ------------------------------------------------------------ 25 | 26 | DROP TABLE IF EXISTS `phinxlog`; 27 | 28 | CREATE TABLE `phinxlog` ( 29 | `version` bigint(20) NOT NULL, 30 | `migration_name` varchar(100) DEFAULT NULL, 31 | `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 32 | `end_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 33 | `breakpoint` tinyint(1) NOT NULL DEFAULT '0', 34 | PRIMARY KEY (`version`) 35 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 36 | 37 | LOCK TABLES `phinxlog` WRITE; 38 | /*!40000 ALTER TABLE `phinxlog` DISABLE KEYS */; 39 | 40 | INSERT INTO `phinxlog` (`version`, `migration_name`, `start_time`, `end_time`, `breakpoint`) 41 | VALUES 42 | (20160713214419,'Users','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 43 | (20160714152505,'UsersData','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 44 | (20160715174200,'Audit','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 45 | (20160717113500,'ConfigData','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 46 | (20160719215200,'OAuth2Apps','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 47 | (20160719222400,'OAuth2Tokens','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 48 | (20160805134100,'Reports','2016-08-14 19:49:14','2016-08-14 19:49:14',0), 49 | (20160829172800,'Assets','2016-08-29 17:47:39','2016-08-29 17:47:39',0); 50 | 51 | /*!40000 ALTER TABLE `phinxlog` ENABLE KEYS */; 52 | UNLOCK TABLES; 53 | 54 | 55 | 56 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 57 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 58 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 59 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 60 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 61 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 62 | -------------------------------------------------------------------------------- /data/phinx: -------------------------------------------------------------------------------- 1 | ../lib/robmorgan/phinx/bin/phinx -------------------------------------------------------------------------------- /data/phinx.yml: -------------------------------------------------------------------------------- 1 | paths: 2 | migrations: %%PHINX_CONFIG_DIR%%/db/migrations 3 | seeds: %%PHINX_CONFIG_DIR%%/db/seeds 4 | 5 | environments: 6 | default_migration_table: phinxlog 7 | default_database: development 8 | production: 9 | adapter: mysql 10 | host: localhost 11 | name: production_db 12 | user: root 13 | pass: root 14 | port: 3306 15 | charset: utf8 16 | 17 | development: 18 | adapter: mysql 19 | host: 127.0.0.1 20 | name: development_db 21 | user: root 22 | pass: root 23 | port: 3306 24 | charset: utf8 25 | 26 | testing: 27 | adapter: mysql 28 | host: 127.0.0.1 29 | name: testing_db 30 | user: root 31 | pass: root 32 | port: 3306 33 | charset: utf8 34 | -------------------------------------------------------------------------------- /docs/CLI.md: -------------------------------------------------------------------------------- 1 | # Running from the Command-Line 2 | 3 | The CLI uses [Climate](http://climate.thephpleague.com/) for the CLI utility methods. 4 | 5 | From the base folder run: 6 | 7 | ``` 8 | php app/lib/FFMVC/CLI.php / 9 | ``` 10 | 11 | The output will be: 12 | 13 | ``` 14 | CLI Script 15 | FFMVC\CLI\Index::index 16 | Hello World! 17 | Finished. 18 | Script executed in 0.048 seconds. 19 | Memory used 2.29 MB. 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/CREDITS.md: -------------------------------------------------------------------------------- 1 | # APPLICATION TEAM 2 | 3 | * Vijay Mahrra -- vijay@yoyo.org -- @vijinh0 4 | 5 | # CONTRIBUTORS 6 | 7 | * Alexandre Plennevaux -- https://github.com/pixeline 8 | 9 | # SOFTWARE PROJECTS 10 | 11 | * Fat-Free Framework - http://fatfreeframework.com/ 12 | * Materialize -- http://materializecss.com 13 | -------------------------------------------------------------------------------- /docs/GUIDE.md: -------------------------------------------------------------------------------- 1 | # Guide 2 | 3 | # F3 Hive Variables 4 | 5 | - **HOMEDIR** - top level folder for the project (above the www folder) 6 | - **cfg** - extra configuration values loaded from the config_data table. cfg.keys[load,cli,www,cms,api] values are which keys to load at startup defined in the ini 7 | - **uuid** - this is always set as the currently authanticated user (user is logged-in if set) 8 | - **user** - this is always set as an array of the current user (user table row plus anything from users_data which might be useful to have on each request) 9 | - **usersMapper** - mapper of the logged in user 10 | - **userScopes** - scopes the user is a member of (user -regular user,api - api access granted,admin - cms user,root - superuser) 11 | - **isAdmin** - whether or not the user is an admin (member of admin group) - can access cms 12 | - **isRoot** - whether the user is a super-user - can do anything in the cms 13 | - **apiEnabled** - whether the user has api access group memebership 14 | 15 | ## Admin 16 | 17 | - **breadcrumbs** - array of breadcrumbs in format [text => url] 18 | 19 | ## API 20 | 21 | When using the API, these hive variables are set: 22 | 23 | - **api_app** - the registered api app (row from table: oauth2_apps) as an array 24 | - **access_token** - the user's access token if set 25 | - **user_scopes** - scopes of the user 26 | -------------------------------------------------------------------------------- /docs/I18N.md: -------------------------------------------------------------------------------- 1 | # Internationalisation (i18n) 2 | 3 | The language is set using `language=XX` in the incoming request and this sets a session variable `language`. 4 | If the session variable isn't set, the client-browser language string from the f3 variable LANGUAGE is used. 5 | *Note* that the f3 var LANG is set and used rather than LANGUAGE to ensure the language is 2 characters and a single entry. 6 | 7 | ## Translations 8 | 9 | Translations with the main application are made using GNU gettext. Templates can use it also or can be re-written specifically in a different language. If no template file exists in the target language, the default 'en' version is used. 10 | 11 | To create text for translation, wrap the string in `_()`, e.g. `_("Hello")` 12 | 13 | PHP comments on the preceding line are included in the translation `.pot` file. 14 | 15 | e.g. 16 | 17 | ``` 18 | // 'free' is meant in the context of libre in this case 19 | $message = _("The source-code is free."); 20 | ``` 21 | 22 | ### Translating Routes 23 | 24 | Copy the routes to translate from `app/config/routes-en.ini` to `app/config/routes-XX.ini` where XX contains the translated routes in the target language. 25 | 26 | ### Translating Templates 27 | 28 | Copy the folders/paths to translate from `app/templates/en` to `app/templates/XX` where XX is the target language. 29 | 30 | ### Translating Application Strings 31 | 32 | Scan files for strings and create the `messages.po` output file. 33 | 34 | ### gettext - Initial Setup 35 | 36 | From the project root folder execute: 37 | 38 | ``` 39 | > xgettext --from-code=UTF-8 -d i18n -c -i -s -L php -D . -o app/i18n/messages.pot `find app/ -type f -iname "*.ph*"` 40 | ``` 41 | 42 | Use `-j` option to join to an existing file. 43 | 44 | ``` 45 | > mkdir -p app/i18n/en/LC_MESSAGES app/i18n/es/LC_MESSAGES 46 | > find app/i18n -type d -name LC_MESSAGES -exec cp app/i18n/messages.pot {}/ \; 47 | > find app/i18n -type d -name LC_MESSAGES -exec msgfmt {}/messages.pot -o {}/messages.mo \; 48 | ``` 49 | 50 | ### gettext - Updating translations 51 | -------------------------------------------------------------------------------- /docs/ROADMAP.md: -------------------------------------------------------------------------------- 1 | # ROAD MAP # 2 | 3 | -------------------------------------------------------------------------------- /docs/TESTING.md: -------------------------------------------------------------------------------- 1 | # Test Environment 2 | 3 | ## F3 Unit Tests 4 | 5 | Require the file `tests/setup.php` which contains the function `setup()` which will do the following: 6 | 7 | - Setup the base application environment 8 | - Read the `dsn_test` database DSN value from the config.ini 9 | - Delete all existing tables in the test database 10 | - Execute Setup::database from `app/lib/FFCMS/Setup.php` which will import the sql dump from `data/db/sql/create.sql` and create a new root user and api app for that user. 11 | - It then returns an instance of $f3 which can be used by the test suite 12 | 13 | This environment can then be used for safe testing which doesn't interfere with the running website. 14 | 15 | ### Run the test database setup and checks 16 | 17 | ``` 18 | cd tests 19 | php setuptest.php 20 | ``` 21 | 22 | ## Codeception Tests 23 | 24 | This runs on the configured main site, not using the test database. 25 | 26 | Codeception PHP Testing Framework is designed to work just out of the box. This means its installation requires minimal steps and no external dependencies preinstalled (except PHP, of course). Only one configuration step should be taken and you are ready to test your web application from an eye of actual user. 27 | 28 | [Codeception Quickstart](http://codeception.com/quickstart) 29 | 30 | ### System-wide installation 31 | ``` 32 | sudo curl -LsS http://codeception.com/codecept.phar -o /usr/local/bin/codecept 33 | sudo chmod a+x /usr/local/bin/codecept 34 | ``` 35 | 36 | ### Running Tests 37 | 38 | ``` 39 | cd tests 40 | codecept run 41 | ``` 42 | 43 | #### Acceptance Test Output 44 | 45 | ``` 46 | Codeception PHP Testing Framework v2.2.4 47 | Powered by PHPUnit 5.4.8 by Sebastian Bergmann and contributors. 48 | 49 | Acceptance Tests (7) ✔ AdminLoginCept: Check admin login works. (0.28s) 50 | ✔ ForgotPasswordCept: Check forgot password works. (0.66s) 51 | ✔ MyAccountCept: Check my account page works. (0.32s) 52 | ✔ RegisterAppCept: Check registering an app works. (0.44s) 53 | ✔ RegisterCept: Check registering an account works. (0.25s) 54 | ✔ UpdateMyAccountCept: Check my account updating works. (0.45s) 55 | ✔ WelcomeCept: Ensure homepage works (0.10s) 56 | ``` 57 | 58 | #### API Testing 59 | 60 | `codecept run api` 61 | 62 | ``` 63 | Codeception PHP Testing Framework v2.2.4 64 | Powered by PHPUnit 5.4.8 by Sebastian Bergmann and contributors. 65 | 66 | Api Tests (7) 67 | 68 | ✔ GetUserBearerTokenCept: Get a token using a bearer token. (0.15s) 69 | ✔ GetUserCept: Use basic auth to get user information. (0.07s) 70 | ✔ GetUserClientCredentialsCept: Use basic auth to get user information. (0.09s) 71 | ✔ TokenClientCredentialsCept: Get a token using client credentials grant type. (0.08s) 72 | ✔ TokenPasswordCredentialsCept: Get a token using password credentials grant type. (0.07s) 73 | ✔ TokenRefreshCept: Get a token using client credentials grant type and refresh it. (0.14s) 74 | ✔ TokenRevokeCept: Get access/refresh tokens using client credentials grant type and revoke it. (0.14s) 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/TODO.md: -------------------------------------------------------------------------------- 1 | # Todo 2 | 3 | ## Admin 4 | 5 | - Upload Assets 6 | - Table and CRUD for pieces of content (markdown) 7 | - Sortable columns in listing pages 8 | - Chooseable group by/order by options 9 | - More search options 10 | 11 | ### Pages (Admin) 12 | 13 | - Pages - uploads: add banner image(s) and main image 14 | - Pages - uploads: add random files 15 | 16 | ## Website 17 | 18 | - Add blog/news page templates for cms pages 19 | - Contact form and map 20 | - Language selector 21 | 22 | ## User Area 23 | 24 | - Javascript image cropping/uploading 25 | 26 | ## API 27 | 28 | - API for Pages 29 | - API for Assets 30 | 31 | ## i18n 32 | 33 | - Create a smaple version of the site in Spanish as a proof-of-concept 34 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tests 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/tests/.gitkeep -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | get('db.dsn_test'); 28 | if (!empty($httpDSN)) { 29 | $dbParams = $f3->get('db'); 30 | $params = \FFMVC\Helpers\DB::parseHttpDsn($httpDSN); 31 | $params['dsn'] = \FFMVC\Helpers\DB::createDbDsn($params); 32 | $dbParams = array_merge($dbParams, $params); 33 | $f3->set('db', $dbParams); 34 | } 35 | 36 | // load dependency injection container 37 | $dice = new \Dice\Dice; 38 | 39 | // logging for application 40 | $logfile = $f3->get('log.file'); 41 | $dice->addRule('Log', ['shared' => true, 'constructParams' => [$logfile]]); 42 | 43 | // database connection used by app 44 | $dbConfig = $f3->get('db'); 45 | 46 | $dice->addRule('DB\\SQL', ['shared' => true, 'constructParams' => [ 47 | \FFMVC\Helpers\DB::createDbDsn($dbConfig), 48 | $dbConfig['user'], 49 | $dbConfig['pass'], 50 | [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION] 51 | ]]); 52 | 53 | // auto-create database if options set 54 | try { 55 | $db = $dice->create('DB\\SQL'); 56 | \Registry::set('db', $db); 57 | } catch (\PDOException $e) { 58 | switch ($e->getCode()) { 59 | case 1049: // db doesn't exist 60 | die($e->getMessage()); 61 | break; 62 | default: 63 | throw($e); 64 | return; 65 | } 66 | } 67 | 68 | // drop existing tables, re-create db 69 | try { 70 | $results = $db->exec('SHOW TABLES'); 71 | $queries = []; 72 | if (!empty($results)) { 73 | $queries[] = 'SET FOREIGN_KEY_CHECKS = 0'; 74 | foreach ($results as $result) { 75 | foreach ($result as $table) { 76 | $queries[] = sprintf('DROP TABLE IF EXISTS %s', $db->quotekey($table)); 77 | } 78 | } 79 | $queries[] = 'SET FOREIGN_KEY_CHECKS = 1'; 80 | $db->exec($queries); 81 | } 82 | \FFCMS\Setup::database($dice); 83 | \Registry::set('db', $db); 84 | } catch (\PDOException $e) { 85 | throw($e); 86 | } 87 | 88 | return $f3; 89 | } 90 | -------------------------------------------------------------------------------- /tests/setuptest.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php -q 2 | get('CLI'))) { 13 | die('This can only be executed in CLI mode.'); 14 | } 15 | $db = \Registry::get('db'); 16 | } catch (\Exception $e) { 17 | // fatal, can't continue 18 | throw($e); 19 | } 20 | 21 | // load the first user 22 | $test = new \Test; 23 | $usersModel = new Models\Users; 24 | $usersMapper = $usersModel->getMapper(); 25 | $usersMapper->load(['email = ?', $f3->get('email.from')]); 26 | $test->expect( 27 | is_int($usersMapper->id) && $usersMapper->id == 1, 28 | 'Default user was created successfully.' 29 | ); 30 | 31 | // Display the results; not MVC but let's keep it simple 32 | foreach ($test->results() as $result) { 33 | echo $result['text'] . '
'; 34 | if ($result['status']) { 35 | echo 'Pass'; 36 | } else { 37 | echo 'Fail (' . $result['source'] . ')'; 38 | } 39 | echo '
'; 40 | } 41 | -------------------------------------------------------------------------------- /tests/tests/_bootstrap.php: -------------------------------------------------------------------------------- 1 | seeInDatabase('users', ['email' => ADMIN_EMAIL]); 10 | $I->amOnPage('/en/login'); 11 | $I->fillField('#email', ADMIN_EMAIL); 12 | $I->fillField('#password', ADMIN_PASSWORD); 13 | $I->click('#login'); 14 | $I->see('Admin'); 15 | $I->see('Hello'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/tests/_support/Step/Acceptance/Register.php: -------------------------------------------------------------------------------- 1 | dontSeeInDatabase('users', ['email' => USER_EMAIL]); 10 | $I->amOnPage('/en/register'); 11 | $I->see('Register'); 12 | $I->fillField('#email', USER_EMAIL); 13 | $I->fillField('#password', USER_PASSWORD); 14 | $I->fillField('#confirm_password', USER_PASSWORD); 15 | $I->fillField('#firstname', USER_FORENAME); 16 | $I->fillField('#lastname', USER_SURNAME); 17 | $I->fillField('#password_question', USER_PW_QUESTION); 18 | $I->fillField('#password_answer', USER_PW_ANSWER); 19 | $I->click('#register'); 20 | $I->see('Hello'); 21 | $I->see('You successfully registered'); 22 | $I->see('My Account'); 23 | $I->seeInDatabase('users', ['email' => USER_EMAIL]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/tests/_support/UnitTester.php: -------------------------------------------------------------------------------- 1 | wantTo('Check admin login works.'); 6 | $I->loginAsAdmin(); 7 | -------------------------------------------------------------------------------- /tests/tests/acceptance/AdminPagesCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Check admin pages display.'); 6 | $I->loginAsAdmin(); 7 | $I->amOnPage('/en/admin/users/list'); 8 | $I->see('Edit'); 9 | $I->amOnPage('/en/admin/audit/list'); 10 | $I->see('View'); 11 | $I->amOnPage('/en/admin/reports/list'); 12 | $I->see('Report'); 13 | $I->amOnPage('/en/admin/config/list'); 14 | $I->see('Config'); 15 | $I->amOnPage('/en/admin/apps/list'); 16 | $I->see('Edit'); 17 | $I->amOnPage('/en/admin/apps/tokens/list'); 18 | $I->see('App Tokens'); 19 | $I->amOnPage('/en/user/apps'); 20 | $I->see('Admin App'); 21 | $I->see('Approved'); 22 | -------------------------------------------------------------------------------- /tests/tests/acceptance/ForgotPasswordCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Check forgot password works.'); 5 | $I->amOnPage('/en/login'); 6 | $I->click('Forgot Password?'); 7 | $I->see('Forgot Password'); 8 | $I->fillField('#email', ADMIN_EMAIL); 9 | $I->click('#submit'); 10 | $I->see('password reset email'); 11 | $I->seeInDatabase('users_data', [ 12 | 'key' => 'forgot-password-code', 13 | ]); 14 | $code = $I->grabFromDatabase('users_data', 'value', ['key' => 'forgot-password-code']); 15 | $I->amOnPage('/en/forgot_password_step2'); 16 | $I->fillField('#code', $code); 17 | $I->click('submit'); 18 | $I->see('Password code is valid'); 19 | $answer = $I->grabFromDatabase('users', 'password_answer', ['email' => ADMIN_EMAIL]); 20 | $I->fillField('#password_answer', $answer); 21 | $I->fillField('#password', 'password'); 22 | $I->fillField('#confirm_password', 'password'); 23 | $I->click('#submit'); 24 | $I->see('password was updated'); 25 | -------------------------------------------------------------------------------- /tests/tests/acceptance/MyAccountCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Check my account page works.'); 6 | $I->loginAsAdmin(); 7 | $I->click('My Account'); 8 | $I->amOnPage('/en/user/account'); 9 | -------------------------------------------------------------------------------- /tests/tests/acceptance/RegisterAppCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Check registering an app works.'); 6 | $I->registerAsUser(); 7 | $I->click('My Apps'); 8 | $I->see('Create'); 9 | $I->fillField('#name', 'Test App'); 10 | $I->fillField('#description', 'My new amazing Test App'); 11 | $I->fillField('#callback_uri', 'http://f3-cms.local/oauth2/callback'); 12 | $I->click('#submit'); 13 | $I->see('new app has been registered'); 14 | $I->seeInDatabase('oauth2_apps', [ 15 | 'name' => 'Test App' 16 | ]); 17 | -------------------------------------------------------------------------------- /tests/tests/acceptance/RegisterCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Check registering an account works.'); 6 | $I->registerAsUser(); 7 | -------------------------------------------------------------------------------- /tests/tests/acceptance/UpdateMyAccountCept.php: -------------------------------------------------------------------------------- 1 | loginAsAdmin(); 6 | $I->wantTo('Check my account updating works.'); 7 | $I->click('My Account'); 8 | $I->amOnPage('/en/user/account'); 9 | $I->fillField('#old_password', ADMIN_PASSWORD); 10 | $I->fillField('#firstname', 'Arnold'); 11 | $I->fillField('#lastname', 'Rimmer'); 12 | $I->fillField('#password_question', 'Your ship is?'); 13 | $I->fillField('#password_answer', 'Red Dwarf'); 14 | $I->click('#update'); 15 | $I->see('account was updated'); 16 | $I->seeInDatabase('audit', [ 17 | 'actor' => ADMIN_EMAIL, 18 | 'event' => 'user-login' 19 | ]); 20 | -------------------------------------------------------------------------------- /tests/tests/acceptance/WelcomeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Ensure homepage works'); 4 | $I->amOnPage('/en'); 5 | $I->see('Home'); 6 | -------------------------------------------------------------------------------- /tests/tests/acceptance/_bootstrap.php: -------------------------------------------------------------------------------- 1 | wantTo('Get a token using a bearer token.'); 4 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 5 | $I->sendPOST('/oauth2/token', [ 6 | 'grant_type' => 'client_credentials', 7 | ]); 8 | $I->seeResponseCodeIs(200); 9 | $I->seeResponseIsJson(); 10 | $I->seeResponseMatchesJsonType([ 11 | 'access_token' => 'string', 12 | 'refresh_token' => 'string', 13 | ]); 14 | $results = $I->grabDataFromResponseByJsonPath('.'); 15 | $data = $results[0]; 16 | $access_token = $data['access_token']; 17 | $I->amBearerAuthenticated($access_token); 18 | $I->sendGET('/users'); 19 | $I->seeResponseCodeIs(200); 20 | $I->seeResponseIsJson(); 21 | $I->seeResponseMatchesJsonType([ 22 | 'email' => 'string', 23 | ]); 24 | -------------------------------------------------------------------------------- /tests/tests/api/GetUserCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Use Basic Auth to get user information.'); 4 | $I->amHttpAuthenticated(ADMIN_EMAIL, ADMIN_PASSWORD); 5 | $I->sendGET('/users'); 6 | $I->seeResponseCodeIs(200); 7 | $I->seeResponseIsJson(); 8 | $I->seeResponseContainsJson([ 9 | 'email' => ADMIN_EMAIL 10 | ]); 11 | -------------------------------------------------------------------------------- /tests/tests/api/GetUserClientCredentialsCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Use Basic Auth to get user information.'); 4 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 5 | $I->sendGET('/users'); 6 | $I->seeResponseCodeIs(200); 7 | $I->seeResponseIsJson(); 8 | $I->seeResponseContainsJson([ 9 | 'email' => ADMIN_EMAIL 10 | ]); 11 | -------------------------------------------------------------------------------- /tests/tests/api/TokenClientCredentialsCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Get a token using client credentials grant type.'); 4 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 5 | 6 | $I->sendPOST('/oauth2/token', [ 7 | 'grant_type' => 'client_credentials' 8 | ]); 9 | $I->seeResponseCodeIs(200); 10 | $I->seeResponseIsJson(); 11 | $I->seeResponseMatchesJsonType([ 12 | 'access_token' => 'string', 13 | 'refresh_token' => 'string' 14 | ]); 15 | -------------------------------------------------------------------------------- /tests/tests/api/TokenPasswordCredentialsCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Get a token using password credentials grant type.'); 4 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 5 | 6 | $I->sendPOST('/oauth2/token', [ 7 | 'grant_type' => 'password', 8 | 'client_id' => CLIENT_ID, 9 | 'username' => ADMIN_EMAIL, 10 | 'password' => ADMIN_PASSWORD, 11 | 'scope' => 'read,write' 12 | ]); 13 | $I->seeResponseCodeIs(200); 14 | $I->seeResponseIsJson(); 15 | $I->seeResponseMatchesJsonType([ 16 | 'access_token' => 'string' 17 | ]); 18 | -------------------------------------------------------------------------------- /tests/tests/api/TokenRefreshCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Get a token using client credentials grant type and refresh it.'); 4 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 5 | $I->sendPOST('/oauth2/token', [ 6 | 'grant_type' => 'client_credentials' 7 | ]); 8 | $I->seeResponseCodeIs(200); 9 | $I->seeResponseIsJson(); 10 | $I->seeResponseMatchesJsonType([ 11 | 'access_token' => 'string', 12 | 'refresh_token' => 'string' 13 | ]); 14 | $results = $I->grabDataFromResponseByJsonPath('.'); 15 | $data = $results[0]; 16 | $access_token = $data['access_token']; 17 | $refresh_token = $data['refresh_token']; 18 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 19 | $I->sendPOST('/oauth2/token', [ 20 | 'grant_type' => 'refresh_token', 21 | 'refresh_token' => $refresh_token 22 | ]); 23 | $I->seeResponseCodeIs(200); 24 | $I->seeResponseIsJson(); 25 | $I->seeResponseMatchesJsonType([ 26 | 'access_token' => 'string' 27 | ]); 28 | -------------------------------------------------------------------------------- /tests/tests/api/TokenRevokeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('Get access/refresh tokens using client credentials grant type and revoke it.'); 4 | $I->amHttpAuthenticated(CLIENT_ID, CLIENT_SECRET); 5 | $I->sendPOST('/oauth2/token', [ 6 | 'grant_type' => 'client_credentials' 7 | ]); 8 | $I->seeResponseCodeIs(200); 9 | $I->seeResponseIsJson(); 10 | $I->seeResponseMatchesJsonType([ 11 | 'access_token' => 'string', 12 | 'refresh_token' => 'string' 13 | ]); 14 | $results = $I->grabDataFromResponseByJsonPath('.'); 15 | $data = $results[0]; 16 | $I->sendPOST('/oauth2/revoke', [ 17 | 'token' => $data['access_token'] 18 | ]); 19 | $I->seeResponseCodeIs(200); 20 | $I->seeResponseIsJson(); 21 | $I->seeResponseMatchesJsonType([ 22 | 'revoked' => 'array' 23 | ]); 24 | -------------------------------------------------------------------------------- /tests/tests/api/_bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found 6 | 7 | 53 | 54 | 55 |

Page Not Found

56 |

Sorry, but the page you were trying to view does not exist.

57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /www/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2016 Materialize 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 | -------------------------------------------------------------------------------- /www/README.md: -------------------------------------------------------------------------------- 1 | ![alt tag](https://raw.github.com/dogfalo/materialize/master/images/materialize.gif) 2 | =========== 3 | 4 | [![Travis CI](https://travis-ci.org/Dogfalo/materialize.svg?branch=master)](https://travis-ci.org/Dogfalo/materialize)[![devDependency Status](https://david-dm.org/Dogfalo/materialize/dev-status.svg)](https://david-dm.org/Dogfalo/materialize#info=devDependencies)[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Dogfalo/materialize?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | [Materialize](http://materializecss.com/), a CSS Framework based on material design 7 | 8 | ### Current Version : v0.97.7 9 | 10 | ## Sass Requirements: 11 | - Ruby Sass 3.3+, LibSass 0.6+ 12 | 13 | ## Supported Browsers: 14 | Chrome 35+, Firefox 31+, Safari 7+, IE 10+ 15 | 16 | ## Changelog 17 | - v0.97.7 (July 23rd) 18 | - Basic horizontal cards 19 | - Carousel bug fixes and new features 20 | - Updated sidenav styles and new component 21 | - Meteor package now supports Sass 22 | - Autocomplete form component 23 | - Chips jQuery plugin 24 | - v0.97.6 (April 1st) 25 | - **Removed deprecated material icons from project** 26 | - **Changed /font directory to /fonts** 27 | - Datepicker and ScrollSpy now compatible with jQuery 2.2.x 28 | - Responsive tables now work with empty cells 29 | - Added focus states to checkboxes, switches, and radio buttons 30 | - Sidenav and Modals no longer cause flicker with scrollbar 31 | - Materialbox overflow and z-index issues fixed 32 | - Added new option for Card actions within a Card reveal 33 | - v0.97.5 (Dec 21, 2015) 34 | - Fixed Meteor package crash 35 | - v0.97.4 (Dec 20, 2015) 36 | - Added Jasmine testing with Travis CI 37 | - Select bugfixes 38 | - Grid Offset bugfix 39 | - Dropdown overflow bugfix 40 | - Range slider error bugfix 41 | 42 | 43 | 44 | ## Contributing 45 | [Please read CONTRIBUTING.md for more information](CONTRIBUTING.md) 46 | 47 | ## Testing 48 | We use Jasmine as our testing framework and we're trying to write a robust test suite for our components. If you want to help, [here's a starting guide on how to write tests in Jasmine](https://docs.google.com/document/d/1dVM6qGt_b_y9RRhr9X7oZfFydaJIEqB9CT7yekv-4XE/edit?usp=sharing) 49 | -------------------------------------------------------------------------------- /www/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/apple-touch-icon.png -------------------------------------------------------------------------------- /www/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /www/css/code.css: -------------------------------------------------------------------------------- 1 | code{word-wrap:break-word;color:black}.comment,.doc_comment,.ml_comment{color:dimgray;font-style:italic}.variable{color:blueviolet}.const,.constant_encapsed_string,.class_c,.dir,.file,.func_c,.halt_compiler,.line,.method_c,.lnumber,.dnumber{color:crimson}.string,.and_equal,.boolean_and,.boolean_or,.concat_equal,.dec,.div_equal,.inc,.is_equal,.is_greater_or_equal,.is_identical,.is_not_equal,.is_not_identical,.is_smaller_or_equal,.logical_and,.logical_or,.logical_xor,.minus_equal,.mod_equal,.mul_equal,.ns_c,.ns_separator,.or_equal,.plus_equal,.sl,.sl_equal,.sr,.sr_equal,.xor_equal,.start_heredoc,.end_heredoc,.object_operator,.paamayim_nekudotayim{color:black}.abstract,.array,.array_cast,.as,.break,.case,.catch,.class,.clone,.continue,.declare,.default,.do,.echo,.else,.elseif,.empty.enddeclare,.endfor,.endforach,.endif,.endswitch,.endwhile,.eval,.exit,.extends,.final,.for,.foreach,.function,.global,.goto,.if,.implements,.include,.include_once,.instanceof,.interface,.isset,.list,.namespace,.new,.print,.private,.public,.protected,.require,.require_once,.return,.static,.switch,.throw,.try,.unset,.use,.var,.while{color:royalblue}.open_tag,.open_tag_with_echo,.close_tag{color:orange}.ini_section{color:black}.ini_key{color:royalblue}.ini_value{color:crimson}.xml_tag{color:dodgerblue}.xml_attr{color:blueviolet}.xml_data{color:red}.section{color:black}.directive{color:blue}.data{color:dimgray} 2 | -------------------------------------------------------------------------------- /www/css/style.css: -------------------------------------------------------------------------------- 1 | fieldset { 2 | margin-bottom: 1rem; 3 | } 4 | 5 | ul.footer-copyright { 6 | display: inline; 7 | font-size: 0.85rem; 8 | } 9 | 10 | ul.footer-copyright > li { 11 | display: inline-block; 12 | list-style-type: disc; 13 | } 14 | 15 | ul.footer-copyright > li > a { 16 | color: white; 17 | } 18 | 19 | .text-small { 20 | font-size: 0.75rem; 21 | } 22 | 23 | .text-tiny { 24 | font-size: 0.6rem; 25 | } 26 | 27 | .pagination li a { 28 | padding: 0 9px; 29 | } 30 | -------------------------------------------------------------------------------- /www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/favicon.ico -------------------------------------------------------------------------------- /www/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/favicon.png -------------------------------------------------------------------------------- /www/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /www/fonts/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/fonts/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /www/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # AUTHOR 5 | 6 | Vijay Mahrra -- vijay@yoyo.org -- @vijinh0 7 | 8 | # CONTRIBUTORS 9 | 10 | Alexandre Plennevaux -- https://github.com/pixeline 11 | 12 | # THANKS 13 | 14 | * Fat-Free Framework - http://fatfreeframework.com/ 15 | 16 | # TECHNOLOGY COLOPHON 17 | 18 | * Materialize - http://materializecss.com 19 | * Font Awesome - http://fontawesome.io 20 | -------------------------------------------------------------------------------- /www/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/img/favicon.png -------------------------------------------------------------------------------- /www/img/oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/img/oauth.png -------------------------------------------------------------------------------- /www/index.php: -------------------------------------------------------------------------------- 1 | set('UNLOAD', function () { 25 | \FFMVC\App::finish(); 26 | }); 27 | 28 | // load dependency injection container 29 | $dice = new \Dice\Dice; 30 | 31 | // logging for application 32 | $logfile = $f3->get('log.file'); 33 | $dice->addRule('Log', ['shared' => true, 'constructParams' => [$logfile]]); 34 | 35 | // database connection used by app 36 | $dbConfig = $f3->get('db'); 37 | $dice->addRule('DB\\SQL', ['shared' => true, 'constructParams' => [ 38 | \FFMVC\Helpers\DB::createDbDsn($dbConfig), 39 | $dbConfig['user'], 40 | $dbConfig['pass'], 41 | [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION], 42 | ]]); 43 | 44 | // session handler in db 45 | $dice->addRule('DB\\SQL\\Session', ['shared' => true]); 46 | $session = $dice->create('DB\\SQL\\Session'); 47 | 48 | // auto-create database if options set 49 | \FFCMS\Setup::database($dice); 50 | 51 | // run the main application 52 | require_once 'lib/FFCMS/App.php'; 53 | $app = $dice->create('FFCMS\\App'); 54 | $app->Main(); 55 | } 56 | 57 | // run the application 58 | boot(); 59 | -------------------------------------------------------------------------------- /www/js/site.js: -------------------------------------------------------------------------------- 1 | jQuery(function ($) { 2 | $(".dropdown-button").dropdown(); 3 | $(".button-collapse").sideNav(); 4 | $('select').material_select(); 5 | }); 6 | 7 | function confirmUrl(url, message) { 8 | if (undefined === message) { 9 | message = 'Are you sure?'; 10 | } 11 | if (confirm(message)) { 12 | document.location = url; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /www/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /www/tile-wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/tile-wide.png -------------------------------------------------------------------------------- /www/tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vijinho/f3-cms/49ed38a727ceac5b4a0152817e2a0aab88d88528/www/tile.png --------------------------------------------------------------------------------