Commit 073c3d15 authored by Anton Davydov's avatar Anton Davydov Committed by Rémy Coutable

Initial implementation if license template selector and /licenses/:key API endpoint

parent 06952aaf
...@@ -190,6 +190,9 @@ gem 'babosa', '~> 1.0.2' ...@@ -190,6 +190,9 @@ gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input # Sanitizes SVG input
gem "loofah", "~> 2.0.3" gem "loofah", "~> 2.0.3"
# Working with license
gem 'licensee', "~> 7.0.0"
# Protect against bruteforcing # Protect against bruteforcing
gem "rack-attack", '~> 4.3.1' gem "rack-attack", '~> 4.3.1'
......
...@@ -452,6 +452,8 @@ GEM ...@@ -452,6 +452,8 @@ GEM
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.1.2) letter_opener (1.1.2)
launchy (~> 2.2) launchy (~> 2.2)
licensee (7.0.0)
rugged (~> 0.23)
listen (3.0.5) listen (3.0.5)
rb-fsevent (>= 0.9.3) rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9) rb-inotify (>= 0.9)
...@@ -957,6 +959,7 @@ DEPENDENCIES ...@@ -957,6 +959,7 @@ DEPENDENCIES
jquery-ui-rails (~> 5.0.0) jquery-ui-rails (~> 5.0.0)
kaminari (~> 0.16.3) kaminari (~> 0.16.3)
letter_opener (~> 1.1.2) letter_opener (~> 1.1.2)
licensee (~> 7.0.0)
loofah (~> 2.0.3) loofah (~> 2.0.3)
mail_room (~> 0.6.1) mail_room (~> 0.6.1)
method_source (~> 0.8) method_source (~> 0.8)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
group_projects_path: "/api/:version/groups/:id/projects.json" group_projects_path: "/api/:version/groups/:id/projects.json"
projects_path: "/api/:version/projects.json" projects_path: "/api/:version/projects.json"
labels_path: "/api/:version/projects/:id/labels" labels_path: "/api/:version/projects/:id/labels"
license_path: "/api/:version/licenses/:key"
group: (group_id, callback) -> group: (group_id, callback) ->
url = Api.buildUrl(Api.group_path) url = Api.buildUrl(Api.group_path)
...@@ -92,6 +93,18 @@ ...@@ -92,6 +93,18 @@
).done (projects) -> ).done (projects) ->
callback(projects) callback(projects)
# Return text for specific license
licenseText: (key, fullname, callback) ->
url = Api.buildUrl(Api.license_path)
url = url.replace(':key', key)
$.ajax(
url: url
data:
fullname: fullname
).done (projects) ->
callback(projects)
buildUrl: (url) -> buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root? url = gon.relative_url_root + url if gon.relative_url_root?
return url.replace(':version', gon.api_version) return url.replace(':version', gon.api_version)
class @BlobLicenseSelector
licenseRegex: /^(.+\/)?(licen[sc]e|copying)($|\.)/i
constructor: (editor)->
self = this
@licenseSelector = $('.js-license-selector')
@toggleLicenseSelector($('#file_name').val())
$('#file_name').on 'input', ->
self.toggleLicenseSelector($(this).val())
$('select.license-select').select2(
width: 'resolve'
dropdownAutoWidth: true
placeholder: 'Choose a license template'
).on 'change', (e) ->
Api.licenseText $(this).val(), $(this).data('fullname'), (data) ->
editor.setValue(data, -1)
toggleLicenseSelector: (fileName) =>
if @licenseRegex.test(fileName)
@licenseSelector.show()
else
@licenseSelector.hide()
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
line-height: 42px; line-height: 42px;
padding-top: 7px; padding-top: 7px;
padding-bottom: 7px; padding-bottom: 7px;
.pull-right {
height: 20px;
}
} }
.editor-ref { .editor-ref {
...@@ -53,4 +57,9 @@ ...@@ -53,4 +57,9 @@
.select2 { .select2 {
float: right; float: right;
} }
.encoding-selector,
.license-selector {
display: inline-block;
}
} }
...@@ -122,6 +122,15 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -122,6 +122,15 @@ class Projects::BlobController < Projects::ApplicationController
end end
def editor_variables def editor_variables
@licenses = {
'Popular' => Licensee::License.all(featured: true).map!{ |license| [license.name, license.key] },
'Other' => Licensee::License.all(featured: false).map!{ |license| [license.name, license.key] }
}
unless @repository.empty?
@current_license_key = Licensee.license(@repository.path).try(:key)
end
@target_branch = params[:target_branch] @target_branch = params[:target_branch]
@file_path = @file_path =
......
...@@ -306,6 +306,13 @@ module ProjectsHelper ...@@ -306,6 +306,13 @@ module ProjectsHelper
namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'README.md') namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'README.md')
end end
def new_license_path
ref = @repository.root_ref if @repository
ref ||= 'master'
namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'LICENSE')
end
def last_push_event def last_push_event
if current_user if current_user
current_user.recent_push(@project.id) current_user.recent_push(@project.id)
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
required: true, class: 'form-control new-file-name' required: true, class: 'form-control new-file-name'
.pull-right .pull-right
.license-selector.js-license-selector.hide
= select_tag :license_type, grouped_options_for_select(@licenses, @current_license_key), include_blank: true, class: 'select2 license-select', data: { fullname: @repository.project.creator.name }
.encoding-selector
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2' = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2'
.file-content.code .file-content.code
...@@ -22,3 +26,8 @@ ...@@ -22,3 +26,8 @@
.center .center
%h2 %h2
%i.icon-spinner.icon-spin %i.icon-spinner.icon-spin
:javascript
window.onload = function() {
new BlobLicenseSelector(blob.editor)
}
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
%p %p
If you already have files you can push them using command line instructions below. If you already have files you can push them using command line instructions below.
%p %p
Otherwise you can start with Otherwise you can start with adding
= link_to "adding README", new_readme_path, class: 'underlined-link' = link_to "README", new_readme_path, class: 'underlined-link'
or
= link_to "LICENSE", new_license_path, class: 'underlined-link'
file to this project. file to this project.
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
......
...@@ -57,5 +57,6 @@ module API ...@@ -57,5 +57,6 @@ module API
mount Builds mount Builds
mount Variables mount Variables
mount Runners mount Runners
mount Licenses
end end
end end
module API
# Licenses API
class Licenses < Grape::API
YEAR_TEMPLATE_REGEX = /(\[|<|{)(year|yyyy)(\]|>|})/
FULLNAME_TEMPLATE_REGEX = /\[fullname\]/
# Get text for specific license
#
# Parameters:
# key (required) - The key of a license
# fullname - Reository owner fullname
# Example Request:
# GET /licenses/mit
get 'licenses/:key', requirements: { key: /[\w.-]*/ } do
env['api.format'] = :txt
license = Licensee::License.find(params[:key]).try(:text)
if license
license
.gsub(YEAR_TEMPLATE_REGEX, Time.now.year.to_s)
.gsub(FULLNAME_TEMPLATE_REGEX, params[:fullname])
else
error!('License not found', 404)
end
end
end
end
require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
describe 'GET /licenses/:key' do
before(:each) do
get api("/licenses/#{license_type}?fullname=Anton")
end
context 'for mit license name' do
let(:license_type){ 'mit' }
it 'returns MIT license text and replases template values' do
expect(response.body).to include('Copyright (c) 2016 Anton')
expect(response.body).to include('Copyright (c) 2016')
end
end
context 'for gnu license name' do
let(:license_type){ 'gpl-3.0' }
it 'returns GNU license text and replases template values' do
expect(response.body).to include('GNU GENERAL PUBLIC LICENSE')
expect(response.body).to include('Copyright (C) 2016')
end
end
context 'for apache license name' do
let(:license_type){ 'apache-2.0' }
it 'returns Apache license text and replases template values' do
expect(response.body).to include('Apache License')
expect(response.body).to include('Copyright 2016')
end
end
context 'for mythic license name' do
let(:license_type){ 'muth-over9000' }
it 'returns string with error' do
expect(response).to have_http_status(404)
expect(response.body).to eq 'License not found'
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