From b0457bc7b970009809a72e80387c17c4f7f855b2 Mon Sep 17 00:00:00 2001 From: Joseph Cohen Date: Tue, 17 Feb 2015 16:00:38 -0600 Subject: [PATCH 1/7] Paginate API incidents --- src/Http/Controllers/Api/IncidentController.php | 5 ++++- src/Repositories/EloquentRepository.php | 12 ++++++++++++ src/Repositories/Incident/IncidentRepository.php | 9 +++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Http/Controllers/Api/IncidentController.php b/src/Http/Controllers/Api/IncidentController.php index 07c90089..3cddcc3e 100644 --- a/src/Http/Controllers/Api/IncidentController.php +++ b/src/Http/Controllers/Api/IncidentController.php @@ -3,6 +3,7 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; use CachetHQ\Cachet\Repositories\Incident\IncidentRepository; +use CachetHQ\Cachet\Transformers\IncidentTransformer; use Dingo\Api\Routing\ControllerTrait; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; @@ -37,7 +38,9 @@ class IncidentController extends Controller */ public function getIncidents() { - return $this->incident->all(); + $incidents = $this->incident->paginate(Binput::get('per_page', 20)); + + return $this->response->paginator($incidents, new IncidentTransformer()); } /** diff --git a/src/Repositories/EloquentRepository.php b/src/Repositories/EloquentRepository.php index 772ccfce..d546a268 100644 --- a/src/Repositories/EloquentRepository.php +++ b/src/Repositories/EloquentRepository.php @@ -17,6 +17,18 @@ abstract class EloquentRepository return $this->model->all(); } + /** + * Returns paginated result. + * + * @param int $perPage + * + * @return \Illuminate\Pagination\Paginator + */ + public function paginate($perPage = 20) + { + return $this->model->paginate($perPage); + } + /** * Returns an object with related relationships. * diff --git a/src/Repositories/Incident/IncidentRepository.php b/src/Repositories/Incident/IncidentRepository.php index 2affb747..d0f9bca6 100644 --- a/src/Repositories/Incident/IncidentRepository.php +++ b/src/Repositories/Incident/IncidentRepository.php @@ -11,6 +11,15 @@ interface IncidentRepository */ public function all(); + /** + * Returns paginated result. + * + * @param int $perPage + * + * @return \Illuminate\Pagination\Paginator + */ + public function paginate($perPage = 20); + /** * Create a new model. * From e3bb4a15de59335b85015a5c5929ca9f3d0eb4b1 Mon Sep 17 00:00:00 2001 From: Joseph Cohen Date: Wed, 18 Feb 2015 03:21:30 -0600 Subject: [PATCH 2/7] Component can be created with tags from API --- .../Controllers/Api/ComponentController.php | 22 ++++++++++++++++++- src/Models/Component.php | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Http/Controllers/Api/ComponentController.php b/src/Http/Controllers/Api/ComponentController.php index 3d157b0a..d47582f3 100644 --- a/src/Http/Controllers/Api/ComponentController.php +++ b/src/Http/Controllers/Api/ComponentController.php @@ -3,6 +3,7 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; use CachetHQ\Cachet\Repositories\Component\ComponentRepository; +use CachetHQ\Cachet\Models\Tag; use Dingo\Api\Routing\ControllerTrait; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; @@ -71,7 +72,26 @@ class ComponentController extends Controller */ public function postComponents() { - return $this->component->create($this->auth->user()->id, Binput::all()); + $component = $this->component->create( + $this->auth->user()->id, + Binput::except('tags') + ); + + if (Binput::has('tags')) { + // The component was added successfully, so now let's deal with the tags. + $tags = preg_split('/ ?, ?/', Binput::get('tags')); + + // For every tag, do we need to create it? + $componentTags = array_map(function ($taggable) use ($component) { + return Tag::firstOrCreate([ + 'name' => $taggable, + ])->id; + }, $tags); + + $component->tags()->sync($componentTags); + } + + return $component; } /** diff --git a/src/Models/Component.php b/src/Models/Component.php index 0db18595..df0a0b91 100644 --- a/src/Models/Component.php +++ b/src/Models/Component.php @@ -34,7 +34,7 @@ class Component extends Model implements TransformableInterface protected $rules = [ 'user_id' => 'integer|required', 'name' => 'required', - 'status' => 'integer', + 'status' => 'integer|required', 'link' => 'url', ]; From 42630340dbbf62525f0f401d538d262deba3eb3c Mon Sep 17 00:00:00 2001 From: Joseph Cohen Date: Wed, 18 Feb 2015 03:24:43 -0600 Subject: [PATCH 3/7] CS Fixes --- app/config/packages/dingo/api/config.php | 2 +- app/routes/dashboard.php | 2 +- src/Http/Controllers/Api/ComponentController.php | 2 +- src/Http/Controllers/DashUserController.php | 2 +- src/Http/Controllers/SetupController.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/config/packages/dingo/api/config.php b/app/config/packages/dingo/api/config.php index c67db75c..cdf0f1b0 100644 --- a/app/config/packages/dingo/api/config.php +++ b/app/config/packages/dingo/api/config.php @@ -154,6 +154,6 @@ return [ 'json' => new Dingo\Api\Http\ResponseFormat\JsonResponseFormat(), - ] + ], ]; diff --git a/app/routes/dashboard.php b/app/routes/dashboard.php index e3d7a290..71d59ccb 100644 --- a/app/routes/dashboard.php +++ b/app/routes/dashboard.php @@ -93,7 +93,7 @@ Route::group(['before' => 'auth', 'prefix' => 'dashboard', 'namespace' => 'Cache Route::group(['before' => 'admin'], function () { Route::get('add', [ 'as' => 'dashboard.team.add', - 'uses' => 'DashTeamController@showAddTeamMemberView' + 'uses' => 'DashTeamController@showAddTeamMemberView', ]); Route::get('{user}', 'DashTeamController@showTeamMemberView'); Route::post('add', 'DashTeamController@postAddUser'); diff --git a/src/Http/Controllers/Api/ComponentController.php b/src/Http/Controllers/Api/ComponentController.php index d47582f3..13c1fc6e 100644 --- a/src/Http/Controllers/Api/ComponentController.php +++ b/src/Http/Controllers/Api/ComponentController.php @@ -2,8 +2,8 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; -use CachetHQ\Cachet\Repositories\Component\ComponentRepository; use CachetHQ\Cachet\Models\Tag; +use CachetHQ\Cachet\Repositories\Component\ComponentRepository; use Dingo\Api\Routing\ControllerTrait; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; diff --git a/src/Http/Controllers/DashUserController.php b/src/Http/Controllers/DashUserController.php index a5a2c250..85e1a76b 100644 --- a/src/Http/Controllers/DashUserController.php +++ b/src/Http/Controllers/DashUserController.php @@ -87,7 +87,7 @@ class DashUserController extends Controller public function regenerateApiKey(User $user) { segment_track('User Management', [ - 'event' => 'regenrated_api_token' + 'event' => 'regenrated_api_token', ]); $user->api_key = User::generateApiKey(); diff --git a/src/Http/Controllers/SetupController.php b/src/Http/Controllers/SetupController.php index b1aae56c..1c276d56 100644 --- a/src/Http/Controllers/SetupController.php +++ b/src/Http/Controllers/SetupController.php @@ -88,7 +88,7 @@ class SetupController extends Controller 'settings.show_support' => 'boolean', 'user.username' => 'alpha_num|required', 'user.email' => 'email|required', - 'user.password' => 'required' + 'user.password' => 'required', ]); if ($v->passes()) { From e1cde0e4d075e841bfb365e65f739367dfc50d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Conil?= Date: Wed, 18 Feb 2015 16:21:35 +1100 Subject: [PATCH 4/7] Replace apache with nginx in docker image --- Dockerfile | 61 +++++++++++++++++++++++------------------------ README.md | 5 ++-- nginx-site.conf | 28 ++++++++++++++++++++++ php-fpm-pool.conf | 26 ++++++++++++++++++++ supervisord.conf | 25 +++++++++++++++++++ 5 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 nginx-site.conf create mode 100644 php-fpm-pool.conf create mode 100644 supervisord.conf diff --git a/Dockerfile b/Dockerfile index 18b32821..9557eafa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,4 @@ -FROM php:5.6-apache - -# before building -# run npm install -# run node_modules/.bin/bower install -# run node_modules/.bin/gulp +FROM debian:jessie ENV DB_DRIVER=mysql \ ENV=production \ @@ -11,43 +6,47 @@ ENV DB_DRIVER=mysql \ DB_HOST= \ DB_USERNAME= \ DB_PASSWORD= + COPY . /var/www/html/ WORKDIR /var/www/html/ -RUN curl http://nodejs.org/dist/v0.10.35/node-v0.10.35-linux-x64.tar.gz -o /tmp/nodejs.tar.gz && \ - tar xzf /tmp/nodejs.tar.gz -C /tmp && export PATH=/tmp/node-v0.10.35-linux-x64/bin:$PATH && \ +#using nodesource and debian jessie packages instead of compiling from scratch +RUN DEBIAN_FRONTEND=noninteractive \ + echo "APT::Install-Recommends \"0\";" >> /etc/apt/apt.conf.d/02recommends && \ + echo "APT::Install-Suggests \"0\";" >> /etc/apt/apt.conf.d/02recommends && \ + apt-get -qq update && \ + apt-get -qq install ca-certificates apt-transport-https && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 68576280 && \ + echo 'deb https://deb.nodesource.com/node jessie main' > /etc/apt/sources.list.d/nodesource.list && \ + apt-get -qq update && \ + apt-get -qq install \ + nginx php5-fpm=5.* php5-curl php5-readline php5-mcrypt php5-mysql php5-apcu php5-cli \ + git sqlite libsqlite3-dev nodejs curl supervisor && \ npm install && node_modules/.bin/bower install --allow-root && node_modules/.bin/gulp && \ - rm -rf /tmp/* node_modules/ + rm -rf /tmp/* node_modules/ && \ + apt-get clean && \ + rm -r /var/lib/apt/lists/* && \ + chown -R www-data /var/www/html + # ensure the assets have been compiled RUN for d in public/{build,css,js} ; do test ! -d public/build && \ echo "Run 'gulp' before building container" >&2 && exit 1 || : ; done -RUN apt-get update && \ - apt-get install -y curl libmcrypt-dev zlib1g-dev libxml2-dev \ - git sqlite libsqlite3-dev --no-install-recommends && \ - rm -r /var/lib/apt/lists/* - # hardcode the Illuminate key in app/config/app.php. If you want security, feel free # to override the key in your own container with a 'php artisan key:generate' :) RUN sed -i "s/'key' => '\w.*/'key' => 'f20d3e5ae02125a94bd60203a4edfbde',/" app/config/app.php && \ grep key app/config/app.php -# Override the apache.conf in php:5.4-apache to point to the proper DocumentRoot -# TODO this is pretty brittle and may break if php:5.4-apache changes -RUN sed -i 's/^DocumentRoot .*/DocumentRoot \/var\/www\/html\/public/' /etc/apache2/apache2.conf && \ - grep /var/www/html/public /etc/apache2/apache2.conf -# public/.htaccess needs to use rewrite to let laravel do its thang -RUN a2enmod rewrite +# copy the various nginx and supervisor conf (to handle both fpm and nginx) +RUN sed -i -e "s/;daemonize\s*=\s*yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf ;\ + echo "daemon off;" >> /etc/nginx/nginx.conf ;\ + ln -sf /var/www/html/php-fpm-pool.conf /etc/php5/fpm/pool.d/www.conf ;\ + rm -f /etc/nginx/sites-enabled/* && rm -f /etc/nginx/conf.d/* && ln -sf /var/www/html/nginx-site.conf /etc/nginx/conf.d/default.conf -# install dependencies. Note: PDO and XML are already in this base image -RUN docker-php-ext-install zip && \ - docker-php-ext-install mcrypt && \ - docker-php-ext-install mbstring && \ - docker-php-ext-install pdo_mysql -RUN curl http://pecl.php.net/get/apcu-4.0.7.tgz -o /usr/src/php/ext/apcu.tar.gz && \ - tar xzvf /usr/src/php/ext/apcu.tar.gz -C /usr/src/php/ext && \ - mv /usr/src/php/ext/apcu-4.0.7 /usr/src/php/ext/apcu && \ - docker-php-ext-install apcu -RUN curl -sS https://getcomposer.org/installer | php -RUN php composer.phar install --no-dev -o +RUN curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-dev -o +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf + +EXPOSE 8000 + +CMD ["/usr/bin/supervisord"] diff --git a/README.md b/README.md index 2e7ced82..ec10c470 100644 --- a/README.md +++ b/README.md @@ -53,14 +53,15 @@ Run a DB container (you can either pass in environment variables for the DB, or ```bash $ export DB_USERNAME=cachet $ export DB_PASSWORD=cachet +$ export DB_ROOT_PASSWORD=cachet $ export DB_DATABASE=cachet -$ docker run --name mysql -e MYSQL_USER=$DB_USERNAME -e MYSQL_PASSWORD=$DB_PASSWORD -e MYSQL_DATABASE=$DB_DATABASE -d mysql +$ docker run --name mysql -e MYSQL_USER=$DB_USERNAME -e MYSQL_PASSWORD=$DB_PASSWORD -e MYSQL_ROOT_PASSWORD=$DB_ROOT_PASSWORD -e MYSQL_DATABASE=$DB_DATABASE -d mysql ``` Initialize the DB if you havent yet: ```bash -$ docker run --link mysql:mysql -e DB_HOST=mysql -e DB_DATABASE=$DB_DATABASE -e DB_USERNAME=$DB_USERNAME -e DB_PASSWORD=$DB_PASSWORD cachethq/cachet:latest php artisan migrate +$ docker run --link mysql:mysql -e DB_HOST=mysql -e DB_DATABASE=$DB_DATABASE -e DB_USERNAME=$DB_USERNAME -e DB_PASSWORD=$DB_PASSWORD cachethq/cachet:latest php artisan migrate --force ``` Run Cachet: diff --git a/nginx-site.conf b/nginx-site.conf new file mode 100644 index 00000000..c0a8b9f4 --- /dev/null +++ b/nginx-site.conf @@ -0,0 +1,28 @@ +server { + listen 8000 default; ## listen for ipv4; this line is default and implied + + + root /var/www/html/public; + index index.php; + + # Make site accessible from http://localhost/ + server_name localhost; + + location / { + try_files $uri /index.php$is_args$args; + } + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + location ~ \.php$ { + + include fastcgi_params; + fastcgi_pass 127.0.0.1:9000; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_index index.php; + fastcgi_keep_conn on; + + } + + +} diff --git a/php-fpm-pool.conf b/php-fpm-pool.conf new file mode 100644 index 00000000..ba5d3abf --- /dev/null +++ b/php-fpm-pool.conf @@ -0,0 +1,26 @@ +[www] + +user = www-data +group = www-data + +listen = 127.0.0.1:9000 + +request_terminate_timeout = 120s + +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +chdir = / + +env[DB_DRIVER] = $DB_DRIVER +env[DB_HOST] = $DB_HOST +env[DB_DATABASE] = $DB_DATABASE +env[DB_USERNAME] = $DB_USERNAME +env[DB_PASSWORD] = $DB_PASSWORD + + +[global] + +daemonize = no diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 00000000..d0cef069 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,25 @@ +[unix_http_server] +file=/var/run/supervisor.sock ; (the path to the socket file) + +[supervisord] +logfile=/dev/null ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=0 ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=0 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=true ; (start in foreground if true;default false) + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket + +[program:php5-fpm] +command=/usr/sbin/php5-fpm -c /etc/php5/fpm + +[program:nginx] +command=/usr/sbin/nginx From c44f8228f5168b7bea622e92e597d37c9aa476ea Mon Sep 17 00:00:00 2001 From: Joseph Cohen Date: Thu, 19 Feb 2015 02:39:32 -0600 Subject: [PATCH 5/7] Fixes on nginx and CS --- Dockerfile | 6 +++--- nginx-site.conf | 42 ++++++++++++++++++++++-------------------- php-fpm-pool.conf | 2 -- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9557eafa..b138fdca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ ENV DB_DRIVER=mysql \ COPY . /var/www/html/ WORKDIR /var/www/html/ -#using nodesource and debian jessie packages instead of compiling from scratch +# Using nodesource and debian jessie packages instead of compiling from scratch RUN DEBIAN_FRONTEND=noninteractive \ echo "APT::Install-Recommends \"0\";" >> /etc/apt/apt.conf.d/02recommends && \ echo "APT::Install-Suggests \"0\";" >> /etc/apt/apt.conf.d/02recommends && \ @@ -28,11 +28,11 @@ RUN DEBIAN_FRONTEND=noninteractive \ rm -r /var/lib/apt/lists/* && \ chown -R www-data /var/www/html -# ensure the assets have been compiled +# Ensure the assets have been compiled RUN for d in public/{build,css,js} ; do test ! -d public/build && \ echo "Run 'gulp' before building container" >&2 && exit 1 || : ; done -# hardcode the Illuminate key in app/config/app.php. If you want security, feel free +# Hardcode the Illuminate key in app/config/app.php. If you want security, feel free # to override the key in your own container with a 'php artisan key:generate' :) RUN sed -i "s/'key' => '\w.*/'key' => 'f20d3e5ae02125a94bd60203a4edfbde',/" app/config/app.php && \ grep key app/config/app.php diff --git a/nginx-site.conf b/nginx-site.conf index c0a8b9f4..e9610b17 100644 --- a/nginx-site.conf +++ b/nginx-site.conf @@ -1,28 +1,30 @@ server { - listen 8000 default; ## listen for ipv4; this line is default and implied + listen 8000 default; ## Listen for ipv4; this line is default and implied + + # Make site accessible from http://localhost/ + server_name localhost; + root /var/www/html/public; + index index.html index.htm index.php; - root /var/www/html/public; - index index.php; + charset utf-8; - # Make site accessible from http://localhost/ - server_name localhost; + location / { + try_files $uri $uri/ /index.php?$query_string; + } - location / { - try_files $uri /index.php$is_args$args; - } - - # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 - # - location ~ \.php$ { - - include fastcgi_params; - fastcgi_pass 127.0.0.1:9000; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.php; - fastcgi_keep_conn on; - - } + # Pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + include fastcgi_params; + fastcgi_pass 127.0.0.1:9000; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_index index.php; + fastcgi_keep_conn on; + } + location ~ /\.ht { + deny all; + } } diff --git a/php-fpm-pool.conf b/php-fpm-pool.conf index ba5d3abf..e946bf00 100644 --- a/php-fpm-pool.conf +++ b/php-fpm-pool.conf @@ -1,5 +1,4 @@ [www] - user = www-data group = www-data @@ -22,5 +21,4 @@ env[DB_PASSWORD] = $DB_PASSWORD [global] - daemonize = no From 90cca4abf9d0befa32011831d29d34374423ecdf Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 19 Feb 2015 19:49:57 +1100 Subject: [PATCH 6/7] Add recommendation to run with SSL in production --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ec10c470..9092201c 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ $ docker run -d --name cachet --link mysql:mysql -p 80:80 -e DB_HOST=mysql -e DB Now go to `http:///setup` and have fun! +Note: When running in production you should ensure that you enable SSL. +This is commonly achieved by running Nginx with your certificates on your Docker host, service or load balancers infront of the running container, or by adding your custom SSL certificates and configuration to the supplied Nginx configuration. + + ## Translations A special thank you to our [translators](https://crowdin.com/project/cachet/activity_stream), who have allowed us to share Cachet with the world. If you'd like to contribute translations, please check out our [CrowdIn project](https://crowdin.com/project/cachet). From cf913979ae4a5893f4b7e74819a788e8db183d84 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Thu, 19 Feb 2015 13:44:22 +0000 Subject: [PATCH 7/7] Added StyleCI badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9092201c..639dc61e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Cachet [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) +[![StyleCI](https://styleci.io/repos/26730195/shield)](https://styleci.io/repos/26730195/) [![Build Status](https://img.shields.io/travis/cachethq/Cachet.svg?style=flat-square)](https://travis-ci.org/cachethq/Cachet) [![Quality Score](https://img.shields.io/scrutinizer/g/cachethq/Cachet.svg?style=flat-square)](https://scrutinizer-ci.com/g/cachethq/Cachet) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)