Commit 814709c4 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch 'feat/appearance-api' into 'master'

Implement application appearance API

See merge request gitlab-org/gitlab!20674
parents ff937a0a c787cb8e
......@@ -18,6 +18,11 @@ class Appearance < ApplicationRecord
validate :single_appearance_row, on: :create
default_value_for :title, ''
default_value_for :description, ''
default_value_for :new_project_guidelines, ''
default_value_for :header_message, ''
default_value_for :footer_message, ''
default_value_for :message_background_color, '#E75E40'
default_value_for :message_font_color, '#FFFFFF'
default_value_for :email_header_and_footer_enabled, false
......
---
title: Implement application appearance API endpoint
merge_request: 20674
author: Fabio Huser
type: added
......@@ -105,6 +105,7 @@ The following API resources are available outside of project and group contexts
| Resource | Available endpoints |
|:--------------------------------------------------|:------------------------------------------------------------------------|
| [Appearance](appearance.md) **(CORE ONLY)** | `/application/appearance` |
| [Applications](applications.md) | `/applications` |
| [Audit Events](audit_events.md) **(PREMIUM ONLY)** | `/audit_events` |
| [Avatar](avatar.md) | `/avatar` |
......
# Appearance API **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/16647) in GitLab 12.7.
Appearance API allows you to maintain GitLab's appearance as if using the GitLab UI at
`/admin/appearance`. The API requires administrator privileges.
## Get current appearance configuration
List the current appearance configuration of the GitLab instance.
```
GET /application/appearance
```
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/application/appearance
```
Example response:
```json
{
"title": "GitLab Test Instance",
"description": "gitlab-test.example.com",
"logo": "/uploads/-/system/appearance/logo/1/logo.png",
"header_logo": "/uploads/-/system/appearance/header_logo/1/header.png",
"favicon": "/uploads/-/system/appearance/favicon/1/favicon.png",
"new_project_guidelines": "Please read the FAQs for help.",
"header_message": "",
"footer_message": "",
"message_background_color": "#e75e40",
"message_font_color": "#ffffff",
"email_header_and_footer_enabled": false
}
```
## Change appearance configuration
Use an API call to modify GitLab instance appearance configuration.
```
PUT /application/appearance
```
| Attribute | Type | Required | Description |
| --------------------------------- | ------- | -------- | ----------- |
| `title` | string | no | Instance title on the sign in / sign up page
| `description` | string | no | Markdown text shown on the sign in / sign up page
| `logo` | mixed | no | Instance image used on the sign in / sign up page
| `header_logo` | mixed | no | Instance image used for the main navigation bar
| `favicon` | mixed | no | Instance favicon in .ico/.png format
| `new_project_guidelines` | string | no | Markdown text shown on the new project page
| `header_message` | string | no | Message within the system header bar
| `footer_message` | string | no | Message within the system footer bar
| `message_background_color` | string | no | Background color for the system header / footer bar
| `message_font_color` | string | no | Font color for the system header / footer bar
| `email_header_and_footer_enabled` | boolean | no | Add header and footer to all outgoing emails if enabled
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/application/appearance?email_header_and_footer_enabled=true&header_message=test
```
Example response:
```json
{
"title": "GitLab Test Instance",
"description": "gitlab-test.example.com",
"logo": "/uploads/-/system/appearance/logo/1/logo.png",
"header_logo": "/uploads/-/system/appearance/header_logo/1/header.png",
"favicon": "/uploads/-/system/appearance/favicon/1/favicon.png",
"new_project_guidelines": "Please read the FAQs for help.",
"header_message": "test",
"footer_message": "",
"message_background_color": "#e75e40",
"message_font_color": "#ffffff",
"email_header_and_footer_enabled": true
}
```
......@@ -104,6 +104,7 @@ module API
# Keep in alphabetical order
mount ::API::AccessRequests
mount ::API::Appearance
mount ::API::Applications
mount ::API::Avatar
mount ::API::AwardEmoji
......
# frozen_string_literal: true
module API
class Appearance < Grape::API
before { authenticated_as_admin! }
helpers do
def current_appearance
@current_appearance ||= (::Appearance.current || ::Appearance.new)
end
end
desc 'Get the current appearance' do
success Entities::Appearance
end
get "application/appearance" do
present current_appearance, with: Entities::Appearance
end
desc 'Modify appearance' do
success Entities::Appearance
end
params do
optional :title, type: String, desc: 'Instance title on the sign in / sign up page'
optional :description, type: String, desc: 'Markdown text shown on the sign in / sign up page'
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :logo, type: File, desc: 'Instance image used on the sign in / sign up page' # rubocop:disable Scalability/FileUploads
optional :header_logo, type: File, desc: 'Instance image used for the main navigation bar' # rubocop:disable Scalability/FileUploads
optional :favicon, type: File, desc: 'Instance favicon in .ico/.png format' # rubocop:disable Scalability/FileUploads
optional :new_project_guidelines, type: String, desc: 'Markmarkdown text shown on the new project page'
optional :header_message, type: String, desc: 'Message within the system header bar'
optional :footer_message, type: String, desc: 'Message within the system footer bar'
optional :message_background_color, type: String, desc: 'Background color for the system header / footer bar'
optional :message_font_color, type: String, desc: 'Font color for the system header / footer bar'
optional :email_header_and_footer_enabled, type: Boolean, desc: 'Add header and footer to all outgoing emails if enabled'
end
put "application/appearance" do
attrs = declared_params(include_missing: false)
if current_appearance.update(attrs)
present current_appearance, with: Entities::Appearance
else
render_validation_error!(current_appearance)
end
end
end
end
......@@ -1343,6 +1343,30 @@ module API
expose :allow_local_requests_from_web_hooks_and_services, as: :allow_local_requests_from_hooks_and_services
end
class Appearance < Grape::Entity
expose :title
expose :description
expose :logo do |appearance, options|
appearance.logo.url
end
expose :header_logo do |appearance, options|
appearance.header_logo.url
end
expose :favicon do |appearance, options|
appearance.favicon.url
end
expose :new_project_guidelines
expose :header_message
expose :footer_message
expose :message_background_color
expose :message_font_color
expose :email_header_and_footer_enabled
end
# deprecated old Release representation
class TagRelease < Grape::Entity
expose :tag, as: :tag_name
......
# frozen_string_literal: true
require 'spec_helper'
describe API::Appearance, 'Appearance' do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
describe "GET /application/appearance" do
context 'as a non-admin user' do
it "returns 403" do
get api("/application/appearance", user)
expect(response).to have_gitlab_http_status(403)
end
end
context 'as an admin user' do
it "returns appearance" do
get api("/application/appearance", admin)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Hash
expect(json_response['description']).to eq('')
expect(json_response['email_header_and_footer_enabled']).to be(false)
expect(json_response['favicon']).to be_nil
expect(json_response['footer_message']).to eq('')
expect(json_response['header_logo']).to be_nil
expect(json_response['header_message']).to eq('')
expect(json_response['logo']).to be_nil
expect(json_response['message_background_color']).to eq('#E75E40')
expect(json_response['message_font_color']).to eq('#FFFFFF')
expect(json_response['new_project_guidelines']).to eq('')
expect(json_response['title']).to eq('')
end
end
end
describe "PUT /application/appearance" do
context 'as a non-admin user' do
it "returns 403" do
put api("/application/appearance", user), params: { title: "Test" }
expect(response).to have_gitlab_http_status(403)
end
end
context 'as an admin user' do
context "instance basics" do
it "allows updating the settings" do
put api("/application/appearance", admin), params: {
title: "GitLab Test Instance",
description: "gitlab-test.example.com",
new_project_guidelines: "Please read the FAQs for help."
}
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Hash
expect(json_response['description']).to eq('gitlab-test.example.com')
expect(json_response['email_header_and_footer_enabled']).to be(false)
expect(json_response['favicon']).to be_nil
expect(json_response['footer_message']).to eq('')
expect(json_response['header_logo']).to be_nil
expect(json_response['header_message']).to eq('')
expect(json_response['logo']).to be_nil
expect(json_response['message_background_color']).to eq('#E75E40')
expect(json_response['message_font_color']).to eq('#FFFFFF')
expect(json_response['new_project_guidelines']).to eq('Please read the FAQs for help.')
expect(json_response['title']).to eq('GitLab Test Instance')
end
end
context "system header and footer" do
it "allows updating the settings" do
settings = {
footer_message: "This is a Header",
header_message: "This is a Footer",
message_font_color: "#ffffff",
message_background_color: "#009999",
email_header_and_footer_enabled: true
}
put api("/application/appearance", admin), params: settings
expect(response).to have_gitlab_http_status(200)
settings.each do |attribute, value|
expect(Appearance.current.public_send(attribute)).to eq(value)
end
end
context "fails on invalid color values" do
it "with message_font_color" do
put api("/application/appearance", admin), params: { message_font_color: "No Color" }
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['message_font_color']).to contain_exactly('must be a valid color code')
end
it "with message_background_color" do
put api("/application/appearance", admin), params: { message_background_color: "#1" }
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['message_background_color']).to contain_exactly('must be a valid color code')
end
end
end
context "instance logos" do
let_it_be(:appearance) { create(:appearance) }
it "allows updating the image files" do
put api("/application/appearance", admin), params: {
logo: fixture_file_upload("spec/fixtures/dk.png", "image/png"),
header_logo: fixture_file_upload("spec/fixtures/dk.png", "image/png"),
favicon: fixture_file_upload("spec/fixtures/dk.png", "image/png")
}
expect(response).to have_gitlab_http_status(200)
expect(json_response['logo']).to eq("/uploads/-/system/appearance/logo/#{appearance.id}/dk.png")
expect(json_response['header_logo']).to eq("/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png")
expect(json_response['favicon']).to eq("/uploads/-/system/appearance/favicon/#{appearance.id}/dk.png")
end
context "fails on invalid color images" do
it "with string instead of file" do
put api("/application/appearance", admin), params: { logo: 'not-a-file.png' }
expect(response).to have_gitlab_http_status(400)
expect(json_response['error']).to eq("logo is invalid")
end
it "with .svg file instead of .png" do
put api("/application/appearance", admin), params: { favicon: fixture_file_upload("spec/fixtures/logo_sample.svg", "image/svg") }
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['favicon']).to contain_exactly("You are not allowed to upload \"svg\" files, allowed types: png, ico")
end
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment