From 3ab07b8aae8dae43cfa3aae1306c59ea264a8594 Mon Sep 17 00:00:00 2001 From: Bugagazavr Date: Sun, 15 Feb 2015 17:01:27 +0300 Subject: [PATCH 01/10] Update API branches documentation [ci skip] --- doc/api/branches.md | 139 ++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 84 deletions(-) diff --git a/doc/api/branches.md b/doc/api/branches.md index 319f0b4738..6a9c10c852 100644 --- a/doc/api/branches.md +++ b/doc/api/branches.md @@ -15,27 +15,20 @@ Parameters: ```json [ { - "name": "master", "commit": { - "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", - "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, + "author_email": "john@example.com", + "author_name": "John Smith", "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": true } ] @@ -56,27 +49,20 @@ Parameters: ```json { - "name": "master", "commit": { - "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", - "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, + "author_email": "john@example.com", + "author_name": "John Smith", "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": true } ``` @@ -97,27 +83,20 @@ Parameters: ```json { - "name": "master", "commit": { - "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", - "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, + "author_email": "john@example.com", + "author_name": "John Smith", "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": true } ``` @@ -138,27 +117,20 @@ Parameters: ```json { - "name": "master", "commit": { - "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", - "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, + "author_email": "john@example.com", + "author_name": "John Smith", "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": false } ``` @@ -177,21 +149,20 @@ Parameters: ```json { - "name": "my-new-branch", "commit": { - "id": "8848c0e90327a0b70f1865b843fb2fbfb9345e57", - "message": "Merge pull request #54 from brightbox/use_fog_brightbox_module\n\nUpdate to use fog-brightbox module", - "parent_ids": [ - "fff449e0bf453576f16c91d6544f00a2664009d8", - "f93a93626fec20fd659f4ed3ab2e64019b6169ae" - ], - "authored_date": "2014-02-20T19:54:55+02:00", - "author_name": "john smith", "author_email": "john@example.com", - "committed_date": "2014-02-20T19:54:55+02:00", - "committer_name": "john smith", - "committer_email": "john@example.com" + "author_name": "John Smith", + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00", + "committer_email": "john@example.com", + "committer_name": "John Smith", + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "message": "add projects API", + "parent_ids": [ + "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + ] }, + "name": "master", "protected": false } ``` From 9a5199f00577e759b14e1a2058400105f90e7cf4 Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Wed, 18 Feb 2015 19:06:58 +0100 Subject: [PATCH 02/10] Add missing color codes for line anchors, fixes #8628 --- app/assets/stylesheets/highlight/dark.scss | 1 + app/assets/stylesheets/highlight/monokai.scss | 5 +++++ app/assets/stylesheets/highlight/solarized_dark.scss | 5 +++++ app/assets/stylesheets/highlight/solarized_light.scss | 5 +++++ app/assets/stylesheets/highlight/white.scss | 5 +++++ 5 files changed, 21 insertions(+) diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index 4095d35b05..fcd4d47bac 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -12,6 +12,7 @@ border-left: 1px solid #666; } + // highlight line via anchor pre.hll { background-color: #fff !important; } diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 730018e3e2..bcd2e71665 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -12,6 +12,11 @@ border-left: 1px solid #555; } + // highlight line via anchor + pre.hll { + background-color: #49483e !important; + } + .hll { background-color: #49483e } .c { color: #75715e } /* Comment */ .err { color: #960050; background-color: #1e0010 } /* Error */ diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index be6904100e..4a6b759bd2 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -12,6 +12,11 @@ border-left: 1px solid #113b46; } + // highlight line via anchor + pre.hll { + background-color: #073642 !important; + } + /* Solarized Dark For use with Jekyll and Pygments diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 55be6e3038..7254f4d7ac 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -12,6 +12,11 @@ border-left: 1px solid #c5d0d4; } + // highlight line via anchor + pre.hll { + background-color: #eee8d5 !important; + } + /* Solarized Light For use with Jekyll and Pygments diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 050a5d241a..4d6f5dfd91 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -12,6 +12,11 @@ border-left: 1px solid #bbb; } + // highlight line via anchor + pre.hll { + background-color: #f8eec7 !important; + } + .hll { background-color: #f8f8f8 } .c { color: #999988; font-style: italic; } .err { color: #a61717; background-color: #e3d2d2; } From 10e4e2110c388ac43f1ebf437b963f13a1882129 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 18 Feb 2015 20:49:19 -0800 Subject: [PATCH 03/10] Improve the explanation and linking of the Oauth docs. --- doc/README.md | 1 + doc/api/README.md | 3 ++- doc/api/oauth2.md | 11 +++++++---- doc/integration/README.md | 3 +-- doc/integration/external-issue-tracker.md | 3 ++- doc/integration/oauth_provider.md | 6 +++++- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/doc/README.md b/doc/README.md index 932e90e359..59cfe1bb11 100644 --- a/doc/README.md +++ b/doc/README.md @@ -10,6 +10,7 @@ - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects. - [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN. +- [OAuth2 provider](integration/oauth_provider.md) to allow you to login to other applications from GitLab. ## Administrator documentation diff --git a/doc/api/README.md b/doc/api/README.md index 8cbba8598d..dec530d0b8 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -22,6 +22,7 @@ ## Clients Find API Clients for GitLab [on our website](https://about.gitlab.com/applications/#api-clients). +You can use [GitLab as an OAuth2 client](oauth2.md) to make API calls. ## Introduction @@ -67,7 +68,7 @@ curl https://localhost:3000/api/v3/user?access_token=OAUTH-TOKEN curl -H "Authorization: Bearer OAUTH-TOKEN" https://localhost:3000/api/v3/user ``` -Read more about [OAuth2 in GitLab](oauth2.md). +Read more about [GitLab as an OAuth2 client](oauth2.md). ## Status codes diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md index 7bb391054c..d416a826f7 100644 --- a/doc/api/oauth2.md +++ b/doc/api/oauth2.md @@ -1,14 +1,17 @@ -# OAuth2 authentication +# GitLab as an OAuth2 client -OAuth2 is a protocol that enables us to get access to private details of user's account without getting its password. +This document is about using other OAuth authentication service providers to sign into GitLab. +If you want GitLab to be an OAuth authentication service provider to sign into other services please see the [Oauth2 provider documentation](../integration/oauth_provider.md). -Before using the OAuth2 you should create an application in user's account. Each application getting unique App ID and App Secret parameters. You should not share them. +OAuth2 is a protocol that enables us to authenticate a user without requiring them to give their password. + +Before using the OAuth2 you should create an application in user's account. Each application gets a unique App ID and App Secret parameters. You should not share these. This functionality is based on [doorkeeper gem](https://github.com/doorkeeper-gem/doorkeeper) ## Web Application Flow -This flow is using for authentication from third-party web sites and probably is most used. +This flow is using for authentication from third-party web sites and is probably used the most. It basically consists of an exchange of an authorization token for an access token. For more detailed info, check out the [RFC spec here](http://tools.ietf.org/html/rfc6749#section-4.1) This flow consists from 3 steps. diff --git a/doc/integration/README.md b/doc/integration/README.md index 1fc8ab997e..e5f33d8dee 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -8,9 +8,8 @@ See the documentation below for details on how to configure these services. - [LDAP](ldap.md) Set up sign in via LDAP - [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth. - [Slack](slack.md) Integrate with the Slack chat service -- [OAuth2 provider](oauth_provider.md) OAuth2 application creation -Jenkins support is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jenkins.html). +GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html). ## Project services diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index 53d6898b6e..96755707de 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -8,6 +8,8 @@ GitLab has a great issue tracker but you can also use an external issue tracker ![Jira screenshot](jira-integration-points.png) +GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html). + ## Configuration ### Project Service @@ -23,7 +25,6 @@ Fill in the required details on the page: * `issues_url` The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the url. This id is used by GitLab as a placeholder to replace the issue number. * `new_issue_url` This is the URL to create a new issue in Redmine for the project linked to this GitLab project. - ### Service Template It is necessary to configure the external issue tracker per project, because project specific details are needed for the integration with GitLab. diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index 5fdb74a43d..192c321f71 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -1,4 +1,8 @@ -## GitLab as OAuth2 provider +## GitLab as OAuth2 authentication service provider + +This document is about using GitLab as an OAuth authentication service provider to sign into other services. +If you want to use other OAuth authentication service providers to sign into GitLab please see the [OAuth2 client documentation](../api/oauth2.md) + OAuth2 provides client applications a 'secure delegated access' to server resources on behalf of a resource owner. Or you can allow users to sign in to your application with their GitLab.com account. In fact OAuth allows to issue access token to third-party clients by an authorization server, with the approval of the resource owner, or end-user. From ff70d2f24e8b437a4c006b61a9b669309718baad Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 18 Feb 2015 22:06:49 -0800 Subject: [PATCH 04/10] Improve GitLab.com integration documentation --- doc/integration/gitlab.md | 27 ++++++++++++++++----------- doc/integration/gitlab_app.png | Bin 0 -> 55325 bytes 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 doc/integration/gitlab_app.png diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md index b95ef5c0af..87400bed5b 100644 --- a/doc/integration/gitlab.md +++ b/doc/integration/gitlab.md @@ -1,10 +1,13 @@ -# GitLab OAuth2 OmniAuth Provider +# Integrate your server with GitLab.com -To enable the GitLab OmniAuth provider you must register your application with GitLab. GitLab will generate a client ID and secret key for you to use. +Import projects from GitLab.com and login to your GitLab instance with your GitLab.com account. -1. Sign in to GitLab. +To enable the GitLab.com OmniAuth provider you must register your application with GitLab.com. +GitLab.com will generate a application ID and secret key for you to use. -1. Navigate to your settings. +1. Sign in to GitLab.com + +1. Navigate to your profile settings. 1. Select "Applications" in the left menu. @@ -15,17 +18,17 @@ To enable the GitLab OmniAuth provider you must register your application with G - Redirect URI: ``` - http://gitlab.example.com/import/gitlab/callback - http://gitlab.example.com/users/auth/gitlab/callback + http://your-gitlab.example.com/import/gitlab/callback + http://your-gitlab.example.com/users/auth/gitlab/callback ``` The first link is required for the importer and second for the authorization. 1. Select "Submit". -1. You should now see a Application ID and Secret. Keep this page open as you continue configuration. - -1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). Keep this page open as you continue configuration. ![GitHub app](github_app.png) +1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). + Keep this page open as you continue configuration. + ![GitLab app](gitlab_app.png) 1. On your GitLab server, open the configuration file. @@ -43,7 +46,7 @@ To enable the GitLab OmniAuth provider you must register your application with G sudo -u git -H editor config/gitlab.yml ``` -1. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for inital settings. +1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for inital settings. 1. Add the provider configuration: @@ -76,4 +79,6 @@ To enable the GitLab OmniAuth provider you must register your application with G 1. Restart GitLab for the changes to take effect. -On the sign in page there should now be a GitLab icon below the regular sign in form. Click the icon to begin the authentication process. GitLab will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to your GitLab instance and will be signed in. +On the sign in page there should now be a GitLab.com icon below the regular sign in form. +Click the icon to begin the authentication process. GitLab.com will ask the user to sign in and authorize the GitLab application. +If everything goes well the user will be returned to your GitLab instance and will be signed in. diff --git a/doc/integration/gitlab_app.png b/doc/integration/gitlab_app.png new file mode 100644 index 0000000000000000000000000000000000000000..3f9391a821bcb2d625e4c8e4db10f1da66168240 GIT binary patch literal 55325 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 Date: Wed, 18 Feb 2015 22:07:09 -0800 Subject: [PATCH 05/10] Fix broken links in documentation --- doc/README.md | 2 +- doc/integration/github.md | 2 +- doc/integration/omniauth.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/README.md b/doc/README.md index 59cfe1bb11..4e00dceac2 100644 --- a/doc/README.md +++ b/doc/README.md @@ -10,7 +10,7 @@ - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects. - [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN. -- [OAuth2 provider](integration/oauth_provider.md) to allow you to login to other applications from GitLab. +- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab. ## Administrator documentation diff --git a/doc/integration/github.md b/doc/integration/github.md index c9c27859c5..137d7e9d63 100644 --- a/doc/integration/github.md +++ b/doc/integration/github.md @@ -35,7 +35,7 @@ To enable the GitHub OmniAuth provider you must register your application with G sudo -u git -H editor config/gitlab.yml ``` -1. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for inital settings. +1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for inital settings. 1. Add the provider configuration: diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md index 7433de3390..c92fa3ee4b 100644 --- a/doc/integration/omniauth.md +++ b/doc/integration/omniauth.md @@ -70,7 +70,7 @@ Now we can choose one or more of the Supported Providers below to continue confi ## Supported Providers - [GitHub](github.md) -- [GitLab](gitlab.md) +- [GitLab.com](gitlab.md) - [Google](google.md) - [Shibboleth](shibboleth.md) - [Twitter](twitter.md) From 3c2139ed172c607467ec6cf412d7ed33147bac22 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 18 Feb 2015 22:23:24 -0800 Subject: [PATCH 06/10] Fix trending projects ordering --- app/finders/trending_projects_finder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/finders/trending_projects_finder.rb b/app/finders/trending_projects_finder.rb index 32d7968924..a79bd47d98 100644 --- a/app/finders/trending_projects_finder.rb +++ b/app/finders/trending_projects_finder.rb @@ -8,7 +8,7 @@ class TrendingProjectsFinder # for period of time - ex. month projects.joins(:notes).where('notes.created_at > ?', start_date). select("projects.*, count(notes.id) as ncount"). - group("projects.id").order("ncount DESC") + group("projects.id").reorder("ncount DESC") end private From 93e42f690bc057ca0e803074aaeb1b55ea9c2232 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 19 Feb 2015 11:20:58 +0100 Subject: [PATCH 07/10] Document fun facts about omnibus-gitlab --- doc/development/omnibus.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/development/omnibus.md diff --git a/doc/development/omnibus.md b/doc/development/omnibus.md new file mode 100644 index 0000000000..0ba354d28a --- /dev/null +++ b/doc/development/omnibus.md @@ -0,0 +1,32 @@ +# What you should know about omnibus packages + +Most users install GitLab using our omnibus packages. As a developer it can be +good to know how the omnibus packages differ from what you have on your laptop +when you are coding. + +## Files are owned by root by default + +All the files in the Rails tree (`app/`, `config/` etc.) are owned by 'root' in +omnibus installations. This makes the installation simpler and it provides +extra security. The omnibus reconfigure script contains commands that give +write access to the 'git' user only where needed. + +For example, the 'git' user is allowed to write in the `log/` directory, in +`public/uploads`, and they are allowed to rewrite the `db/schema.rb` file. + +In other cases, the reconfigure script tricks GitLab into not trying to write a +file. For instance, GitLab will generate a `.secret` file if it cannot find one +and write it to the Rails root. In the omnibus packages, reconfigure writes the +`.secret` file first, so that GitLab never tries to write it. + +## Code, data and logs are in separate directories + +The omnibus design separates code (read-only, under `/opt/gitlab`) from data +(read/write, under `/var/opt/gitlab`) and logs (read/write, under +`/var/log/gitlab`). To make this happen the reconfigure script sets custom +paths where it can in GitLab config files, and where there are no path +settings, it uses symlinks. + +For example, `config/gitlab.yml` is treated as data so that file is a symlink. +The same goes for `public/uploads`. The `log/` directory is replaced by omnibus +with a symlink to `/var/log/gitlab/gitlab-rails`. From 7c3147e6e969a7ae97e2f8d05e536abeeb7d3936 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 19 Feb 2015 08:57:33 -0800 Subject: [PATCH 08/10] Revert "Nitpicking." This reverts commit ebd39fc082b09177e0777e5de5729c3f98495e87. --- app/controllers/files_controller.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index 15523cbc2e..561af8084c 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -5,10 +5,9 @@ class FilesController < ApplicationController if uploader.file_storage? if can?(current_user, :read_project, note.project) - # Replace old notes location in /public with the new one in / and send the file - path = uploader.file.path.gsub("#{Rails.root}/public", Rails.root.to_s) - disposition = uploader.image? ? 'inline' : 'attachment' + # Replace old notes location in /public with the new one in / and send the file + path = uploader.file.path.gsub("#{Rails.root}/public",Rails.root.to_s) send_file path, disposition: disposition else not_found! From 8184a6564454faf0f9ae9dfee1377c3407d08447 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 19 Feb 2015 08:57:35 -0800 Subject: [PATCH 09/10] Revert "Fix broken access control and refactor avatar upload" This reverts commit 7d5f86f6cbd187e75a6ba164ad6bfd036977dd07. --- app/controllers/files_controller.rb | 4 +- app/models/group.rb | 2 +- app/models/project.rb | 2 +- app/models/user.rb | 2 +- app/uploaders/attachment_uploader.rb | 8 +++- app/uploaders/avatar_uploader.rb | 32 --------------- db/migrate/20150213111727_move_note_folder.rb | 19 --------- features/steps/groups.rb | 2 +- features/steps/profile/profile.rb | 2 +- features/steps/project/project.rb | 2 +- lib/backup/manager.rb | 2 +- lib/backup/uploads.rb | 40 ++++++------------- uploads/.gitkeep | 0 13 files changed, 27 insertions(+), 90 deletions(-) delete mode 100644 app/uploaders/avatar_uploader.rb delete mode 100644 db/migrate/20150213111727_move_note_folder.rb delete mode 100644 uploads/.gitkeep diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index 561af8084c..9671245d3f 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -6,9 +6,7 @@ class FilesController < ApplicationController if uploader.file_storage? if can?(current_user, :read_project, note.project) disposition = uploader.image? ? 'inline' : 'attachment' - # Replace old notes location in /public with the new one in / and send the file - path = uploader.file.path.gsub("#{Rails.root}/public",Rails.root.to_s) - send_file path, disposition: disposition + send_file uploader.file.path, disposition: disposition else not_found! end diff --git a/app/models/group.rb b/app/models/group.rb index da9621a2a1..d6ec0be608 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -23,7 +23,7 @@ class Group < Namespace validate :avatar_type, if: ->(user) { user.avatar_changed? } validates :avatar, file_size: { maximum: 200.kilobytes.to_i } - mount_uploader :avatar, AvatarUploader + mount_uploader :avatar, AttachmentUploader after_create :post_create_hook after_destroy :post_destroy_hook diff --git a/app/models/project.rb b/app/models/project.rb index e2c7f76eb0..56e1aa2904 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -138,7 +138,7 @@ class Project < ActiveRecord::Base if: ->(project) { project.avatar && project.avatar_changed? } validates :avatar, file_size: { maximum: 200.kilobytes.to_i } - mount_uploader :avatar, AvatarUploader + mount_uploader :avatar, AttachmentUploader # Scopes scope :sorted_by_activity, -> { reorder(last_activity_at: :desc) } diff --git a/app/models/user.rb b/app/models/user.rb index 3bbbd23c1b..a9776b633a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -177,7 +177,7 @@ class User < ActiveRecord::Base end end - mount_uploader :avatar, AvatarUploader + mount_uploader :avatar, AttachmentUploader # Scopes scope :admins, -> { where(admin: true) } diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 22742d287a..b122b6c865 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -3,8 +3,10 @@ class AttachmentUploader < CarrierWave::Uploader::Base storage :file + after :store, :reset_events_cache + def store_dir - "#{Rails.root}/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end def image? @@ -27,4 +29,8 @@ class AttachmentUploader < CarrierWave::Uploader::Base def file_storage? self.class.storage == CarrierWave::Storage::File end + + def reset_events_cache(file) + model.reset_events_cache if model.is_a?(User) + end end diff --git a/app/uploaders/avatar_uploader.rb b/app/uploaders/avatar_uploader.rb deleted file mode 100644 index 7cad044555..0000000000 --- a/app/uploaders/avatar_uploader.rb +++ /dev/null @@ -1,32 +0,0 @@ -# encoding: utf-8 - -class AvatarUploader < CarrierWave::Uploader::Base - storage :file - - after :store, :reset_events_cache - - def store_dir - "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" - end - - def image? - img_ext = %w(png jpg jpeg gif bmp tiff) - if file.respond_to?(:extension) - img_ext.include?(file.extension.downcase) - else - # Not all CarrierWave storages respond to :extension - ext = file.path.split('.').last.downcase - img_ext.include?(ext) - end - rescue - false - end - - def file_storage? - self.class.storage == CarrierWave::Storage::File - end - - def reset_events_cache(file) - model.reset_events_cache if model.is_a?(User) - end -end diff --git a/db/migrate/20150213111727_move_note_folder.rb b/db/migrate/20150213111727_move_note_folder.rb deleted file mode 100644 index ca7f87d984..0000000000 --- a/db/migrate/20150213111727_move_note_folder.rb +++ /dev/null @@ -1,19 +0,0 @@ -class MoveNoteFolder < ActiveRecord::Migration - def up - system( - "if [ -d '#{Rails.root}/public/uploads/note' ]; - then mv #{Rails.root}/public/uploads/note #{Rails.root}/uploads/note; - echo 'note folder has been moved successfully'; - else - echo 'note folder has already been moved or does not exist yet. Nothing to do here.'; fi") - end - - def down - system( - "if [ -d '#{Rails.root}/uploads/note' ]; - then mv #{Rails.root}/uploads/note #{Rails.root}/public/uploads/note; - echo 'note folder has been moved successfully'; - else - echo 'note folder has already been moved or does not exist yet. Nothing to do here.'; fi") - end -end diff --git a/features/steps/groups.rb b/features/steps/groups.rb index 0a9b4ccba5..610e7fd3a4 100644 --- a/features/steps/groups.rb +++ b/features/steps/groups.rb @@ -110,7 +110,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps end step 'I should see new group "Owned" avatar' do - Group.find_by(name: "Owned").avatar.should be_instance_of AvatarUploader + Group.find_by(name: "Owned").avatar.should be_instance_of AttachmentUploader Group.find_by(name: "Owned").avatar.url.should == "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/gitlab_logo.png" end diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb index 4efd217678..a907b0b7dc 100644 --- a/features/steps/profile/profile.rb +++ b/features/steps/profile/profile.rb @@ -29,7 +29,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps end step 'I should see new avatar' do - @user.avatar.should be_instance_of AvatarUploader + @user.avatar.should be_instance_of AttachmentUploader @user.avatar.url.should == "/uploads/user/avatar/#{ @user.id }/gitlab_logo.png" end diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb index d39c8e7d2d..033d45e025 100644 --- a/features/steps/project/project.rb +++ b/features/steps/project/project.rb @@ -35,7 +35,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps end step 'I should see new project avatar' do - @project.avatar.should be_instance_of AvatarUploader + @project.avatar.should be_instance_of AttachmentUploader url = @project.avatar.url url.should == "/uploads/project/avatar/#{ @project.id }/gitlab_logo.png" end diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb index 06cd40a5b1..ab8db4e983 100644 --- a/lib/backup/manager.rb +++ b/lib/backup/manager.rb @@ -1,6 +1,6 @@ module Backup class Manager - BACKUP_CONTENTS = %w{repositories/ db/ public/ uploads/ backup_information.yml} + BACKUP_CONTENTS = %w{repositories/ db/ uploads/ backup_information.yml} def pack # saving additional informations diff --git a/lib/backup/uploads.rb b/lib/backup/uploads.rb index 75d8e18a86..e50e1ff4f1 100644 --- a/lib/backup/uploads.rb +++ b/lib/backup/uploads.rb @@ -1,45 +1,29 @@ module Backup class Uploads - attr_reader :app_public_uploads_dir, :app_private_uploads_dir, :backup_public_uploads_dir, - :backup_private_uploads_dir, :backup_dir, :backup_public_dir + attr_reader :app_uploads_dir, :backup_uploads_dir, :backup_dir def initialize - @app_public_uploads_dir = File.realpath(Rails.root.join('public', 'uploads')) - @app_private_uploads_dir = File.realpath(Rails.root.join('uploads')) + @app_uploads_dir = File.realpath(Rails.root.join('public', 'uploads')) @backup_dir = Gitlab.config.backup.path - @backup_public_dir = File.join(backup_dir, 'public') - @backup_public_uploads_dir = File.join(backup_dir, 'public', 'uploads') - @backup_private_uploads_dir = File.join(backup_dir, 'uploads') + @backup_uploads_dir = File.join(Gitlab.config.backup.path, 'uploads') end - # Copy uploads from public/uploads to backup/public/uploads and from /uploads to backup/uploads + # Copy uploads from public/uploads to backup/uploads def dump - FileUtils.mkdir_p(backup_public_uploads_dir) - FileUtils.cp_r(app_public_uploads_dir, backup_public_dir) - - FileUtils.mkdir_p(backup_private_uploads_dir) - FileUtils.cp_r(app_private_uploads_dir, backup_dir) + FileUtils.mkdir_p(backup_uploads_dir) + FileUtils.cp_r(app_uploads_dir, backup_dir) end def restore - backup_existing_public_uploads_dir - backup_existing_private_uploads_dir + backup_existing_uploads_dir - FileUtils.cp_r(backup_public_uploads_dir, app_public_uploads_dir) - FileUtils.cp_r(backup_private_uploads_dir, app_private_uploads_dir) + FileUtils.cp_r(backup_uploads_dir, app_uploads_dir) end - def backup_existing_public_uploads_dir - timestamped_public_uploads_path = File.join(app_public_uploads_dir, '..', "uploads.#{Time.now.to_i}") - if File.exists?(app_public_uploads_dir) - FileUtils.mv(app_public_uploads_dir, timestamped_public_uploads_path) - end - end - - def backup_existing_private_uploads_dir - timestamped_private_uploads_path = File.join(app_private_uploads_dir, '..', "uploads.#{Time.now.to_i}") - if File.exists?(app_private_uploads_dir) - FileUtils.mv(app_private_uploads_dir, timestamped_private_uploads_path) + def backup_existing_uploads_dir + timestamped_uploads_path = File.join(app_uploads_dir, '..', "uploads.#{Time.now.to_i}") + if File.exists?(app_uploads_dir) + FileUtils.mv(app_uploads_dir, timestamped_uploads_path) end end end diff --git a/uploads/.gitkeep b/uploads/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 From d4e43dc1e6c8d61fcc0bbafbccdda845cb533e08 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 19 Feb 2015 11:58:29 -0800 Subject: [PATCH 10/10] Bump gitlab-shell --- GITLAB_SHELL_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 73462a5a13..aedc15bb0c 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.5.1 +2.5.3