Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce
This commit is contained in:
commit
0430c00cf0
|
@ -51,6 +51,7 @@ v 8.4.0 (unreleased)
|
|||
- Add API support for managing build variables of project
|
||||
- Allow broadcast messages to be edited
|
||||
- Autosize Markdown textareas
|
||||
- Import GitHub wiki into GitLab
|
||||
|
||||
v 8.3.4
|
||||
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)
|
||||
|
@ -88,6 +89,7 @@ v 8.3.0
|
|||
- Add open_issues_count to project API (Stan Hu)
|
||||
- Expand character set of usernames created by Omniauth (Corey Hinshaw)
|
||||
- Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
|
||||
- Add unsubscribe link in the email footer (Zeger-Jan van de Weg)
|
||||
- Provide better diagnostic message upon project creation errors (Stan Hu)
|
||||
- Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu)
|
||||
- Remove api credentials from link to build_page
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#= require latinise
|
||||
|
||||
class @Wikis
|
||||
constructor: ->
|
||||
$('.build-new-wiki').bind "click", (e) ->
|
||||
$('[data-error~=slug]').addClass("hidden")
|
||||
$('p.hint').show()
|
||||
$('.build-new-wiki').bind 'click', (e) =>
|
||||
$('[data-error~=slug]').addClass('hidden')
|
||||
field = $('#new_wiki_path')
|
||||
valid_slug_pattern = /^[\w\/-]+$/
|
||||
slug = @slugify(field.val())
|
||||
|
||||
slug = field.val()
|
||||
if slug.match valid_slug_pattern
|
||||
if (slug.length > 0)
|
||||
path = field.attr('data-wikis-path')
|
||||
if(slug.length > 0)
|
||||
location.href = path + "/" + slug
|
||||
else
|
||||
e.preventDefault()
|
||||
$('p.hint').hide()
|
||||
$('[data-error~=slug]').removeClass("hidden")
|
||||
location.href = path + '/' + slug
|
||||
|
||||
dasherize: (value) ->
|
||||
value.replace(/[_\s]+/g, '-')
|
||||
|
||||
slugify: (value) =>
|
||||
@dasherize(value.trim().toLowerCase().latinise())
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
class SentNotificationsController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
def unsubscribe
|
||||
@sent_notification = SentNotification.for(params[:id])
|
||||
return render_404 unless @sent_notification && @sent_notification.unsubscribable?
|
||||
|
||||
noteable = @sent_notification.noteable
|
||||
noteable.unsubscribe(@sent_notification.recipient)
|
||||
|
||||
flash[:notice] = "You have been unsubscribed from this thread."
|
||||
if current_user
|
||||
case noteable
|
||||
when Issue
|
||||
redirect_to issue_path(noteable)
|
||||
when MergeRequest
|
||||
redirect_to merge_request_path(noteable)
|
||||
else
|
||||
redirect_to root_path
|
||||
end
|
||||
else
|
||||
redirect_to new_user_session_path
|
||||
end
|
||||
end
|
||||
end
|
|
@ -91,7 +91,7 @@ module GitlabMarkdownHelper
|
|||
def render_wiki_content(wiki_page)
|
||||
case wiki_page.format
|
||||
when :markdown
|
||||
markdown(wiki_page.content)
|
||||
markdown(wiki_page.content, pipeline: :wiki, project_wiki: @project_wiki)
|
||||
when :asciidoc
|
||||
asciidoc(wiki_page.content)
|
||||
else
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
module Emails
|
||||
module Issues
|
||||
def new_issue_email(recipient_id, issue_id)
|
||||
issue_mail_with_notification(issue_id, recipient_id) do
|
||||
mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id))
|
||||
end
|
||||
setup_issue_mail(issue_id, recipient_id)
|
||||
|
||||
mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id))
|
||||
end
|
||||
|
||||
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id)
|
||||
issue_mail_with_notification(issue_id, recipient_id) do
|
||||
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
|
||||
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||
end
|
||||
setup_issue_mail(issue_id, recipient_id)
|
||||
|
||||
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
|
||||
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||
end
|
||||
|
||||
def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
|
||||
issue_mail_with_notification(issue_id, recipient_id) do
|
||||
@updated_by = User.find updated_by_user_id
|
||||
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||
end
|
||||
setup_issue_mail(issue_id, recipient_id)
|
||||
|
||||
@updated_by = User.find updated_by_user_id
|
||||
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||
end
|
||||
|
||||
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
|
||||
issue_mail_with_notification(issue_id, recipient_id) do
|
||||
@issue_status = status
|
||||
@updated_by = User.find updated_by_user_id
|
||||
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||
end
|
||||
setup_issue_mail(issue_id, recipient_id)
|
||||
|
||||
@issue_status = status
|
||||
@updated_by = User.find updated_by_user_id
|
||||
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -38,14 +38,12 @@ module Emails
|
|||
}
|
||||
end
|
||||
|
||||
def issue_mail_with_notification(issue_id, recipient_id)
|
||||
def setup_issue_mail(issue_id, recipient_id)
|
||||
@issue = Issue.find(issue_id)
|
||||
@project = @issue.project
|
||||
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
|
||||
|
||||
yield
|
||||
|
||||
SentNotification.record(@issue, recipient_id, reply_key)
|
||||
@sent_notification = SentNotification.record(@issue, recipient_id, reply_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,77 +1,64 @@
|
|||
module Emails
|
||||
module MergeRequests
|
||||
def new_merge_request_email(recipient_id, merge_request_id)
|
||||
@merge_request = MergeRequest.find(merge_request_id)
|
||||
@project = @merge_request.project
|
||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
||||
@project,
|
||||
@merge_request)
|
||||
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||
|
||||
mail_new_thread(@merge_request,
|
||||
from: sender(@merge_request.author_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
|
||||
|
||||
SentNotification.record(@merge_request, recipient_id, reply_key)
|
||||
end
|
||||
|
||||
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id)
|
||||
@merge_request = MergeRequest.find(merge_request_id)
|
||||
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||
|
||||
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
|
||||
@project = @merge_request.project
|
||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
||||
@project,
|
||||
@merge_request)
|
||||
mail_answer_thread(@merge_request,
|
||||
from: sender(updated_by_user_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
|
||||
|
||||
SentNotification.record(@merge_request, recipient_id, reply_key)
|
||||
end
|
||||
|
||||
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
|
||||
@merge_request = MergeRequest.find(merge_request_id)
|
||||
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||
|
||||
@updated_by = User.find updated_by_user_id
|
||||
@project = @merge_request.project
|
||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
||||
@project,
|
||||
@merge_request)
|
||||
mail_answer_thread(@merge_request,
|
||||
from: sender(updated_by_user_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
|
||||
|
||||
SentNotification.record(@merge_request, recipient_id, reply_key)
|
||||
end
|
||||
|
||||
def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
|
||||
@merge_request = MergeRequest.find(merge_request_id)
|
||||
@project = @merge_request.project
|
||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
||||
@project,
|
||||
@merge_request)
|
||||
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||
|
||||
mail_answer_thread(@merge_request,
|
||||
from: sender(updated_by_user_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
|
||||
|
||||
SentNotification.record(@merge_request, recipient_id, reply_key)
|
||||
end
|
||||
|
||||
def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id)
|
||||
@merge_request = MergeRequest.find(merge_request_id)
|
||||
setup_merge_request_mail(merge_request_id, recipient_id)
|
||||
|
||||
@mr_status = status
|
||||
@project = @merge_request.project
|
||||
@updated_by = User.find updated_by_user_id
|
||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
||||
@project,
|
||||
@merge_request)
|
||||
mail_answer_thread(@merge_request,
|
||||
from: sender(updated_by_user_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
|
||||
end
|
||||
|
||||
SentNotification.record(@merge_request, recipient_id, reply_key)
|
||||
private
|
||||
|
||||
def setup_merge_request_mail(merge_request_id, recipient_id)
|
||||
@merge_request = MergeRequest.find(merge_request_id)
|
||||
@project = @merge_request.project
|
||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
||||
@project,
|
||||
@merge_request)
|
||||
|
||||
@sent_notification = SentNotification.record(@merge_request, recipient_id, reply_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
module Emails
|
||||
module Notes
|
||||
def note_commit_email(recipient_id, note_id)
|
||||
note_mail_with_notification(note_id, recipient_id) do
|
||||
@commit = @note.noteable
|
||||
@target_url = namespace_project_commit_url(*note_target_url_options)
|
||||
setup_note_mail(note_id, recipient_id)
|
||||
|
||||
mail_answer_thread(@commit,
|
||||
from: sender(@note.author_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@commit.title} (#{@commit.short_id})"))
|
||||
end
|
||||
@commit = @note.noteable
|
||||
@target_url = namespace_project_commit_url(*note_target_url_options)
|
||||
|
||||
mail_answer_thread(@commit,
|
||||
from: sender(@note.author_id),
|
||||
to: recipient(recipient_id),
|
||||
subject: subject("#{@commit.title} (#{@commit.short_id})"))
|
||||
end
|
||||
|
||||
def note_issue_email(recipient_id, note_id)
|
||||
note_mail_with_notification(note_id, recipient_id) do
|
||||
@issue = @note.noteable
|
||||
@target_url = namespace_project_issue_url(*note_target_url_options)
|
||||
mail_answer_thread(@issue, note_thread_options(recipient_id))
|
||||
end
|
||||
setup_note_mail(note_id, recipient_id)
|
||||
|
||||
@issue = @note.noteable
|
||||
@target_url = namespace_project_issue_url(*note_target_url_options)
|
||||
mail_answer_thread(@issue, note_thread_options(recipient_id))
|
||||
end
|
||||
|
||||
def note_merge_request_email(recipient_id, note_id)
|
||||
note_mail_with_notification(note_id, recipient_id) do
|
||||
@merge_request = @note.noteable
|
||||
@target_url = namespace_project_merge_request_url(*note_target_url_options)
|
||||
mail_answer_thread(@merge_request, note_thread_options(recipient_id))
|
||||
end
|
||||
setup_note_mail(note_id, recipient_id)
|
||||
|
||||
@merge_request = @note.noteable
|
||||
@target_url = namespace_project_merge_request_url(*note_target_url_options)
|
||||
mail_answer_thread(@merge_request, note_thread_options(recipient_id))
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -42,13 +42,11 @@ module Emails
|
|||
}
|
||||
end
|
||||
|
||||
def note_mail_with_notification(note_id, recipient_id)
|
||||
def setup_note_mail(note_id, recipient_id)
|
||||
@note = Note.find(note_id)
|
||||
@project = @note.project
|
||||
|
||||
yield
|
||||
|
||||
SentNotification.record_note(@note, recipient_id, reply_key)
|
||||
@sent_notification = SentNotification.record_note(@note, recipient_id, reply_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -107,10 +107,9 @@ class Notify < BaseMailer
|
|||
end
|
||||
|
||||
headers["X-GitLab-#{model.class.name}-ID"] = model.id
|
||||
headers['X-GitLab-Reply-Key'] = reply_key
|
||||
|
||||
if reply_key
|
||||
headers['X-GitLab-Reply-Key'] = reply_key
|
||||
|
||||
if Gitlab::IncomingEmail.enabled?
|
||||
address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key))
|
||||
address.display_name = @project.name_with_namespace
|
||||
|
||||
|
|
|
@ -119,6 +119,12 @@ module Issuable
|
|||
update(subscribed: !subscribed?(user))
|
||||
end
|
||||
|
||||
def unsubscribe(user)
|
||||
subscriptions.
|
||||
find_or_initialize_by(user_id: user.id).
|
||||
update(subscribed: false)
|
||||
end
|
||||
|
||||
def to_hook_data(user)
|
||||
{
|
||||
object_kind: self.class.name.underscore,
|
||||
|
|
|
@ -38,6 +38,10 @@ class ProjectWiki
|
|||
[Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
|
||||
end
|
||||
|
||||
def wiki_base_path
|
||||
["/", @project.path_with_namespace, "/wikis"].join('')
|
||||
end
|
||||
|
||||
# Returns the Gollum::Wiki object.
|
||||
def wiki
|
||||
@wiki ||= begin
|
||||
|
|
|
@ -25,8 +25,6 @@ class SentNotification < ActiveRecord::Base
|
|||
|
||||
class << self
|
||||
def reply_key
|
||||
return nil unless Gitlab::IncomingEmail.enabled?
|
||||
|
||||
SecureRandom.hex(16)
|
||||
end
|
||||
|
||||
|
@ -59,11 +57,15 @@ class SentNotification < ActiveRecord::Base
|
|||
|
||||
def record_note(note, recipient_id, reply_key, params = {})
|
||||
params[:line_code] = note.line_code
|
||||
|
||||
|
||||
record(note.noteable, recipient_id, reply_key, params)
|
||||
end
|
||||
end
|
||||
|
||||
def unsubscribable?
|
||||
!for_commit?
|
||||
end
|
||||
|
||||
def for_commit?
|
||||
noteable_type == "Commit"
|
||||
end
|
||||
|
@ -75,4 +77,8 @@ class SentNotification < ActiveRecord::Base
|
|||
super
|
||||
end
|
||||
end
|
||||
|
||||
def to_param
|
||||
self.reply_key
|
||||
end
|
||||
end
|
||||
|
|
|
@ -169,7 +169,7 @@ class WikiPage
|
|||
private
|
||||
|
||||
def set_attributes
|
||||
attributes[:slug] = @page.escaped_url_path
|
||||
attributes[:slug] = @page.url_path
|
||||
attributes[:title] = @page.title
|
||||
attributes[:format] = @page.format
|
||||
end
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
%br
|
||||
-# Don't link the host is the line below, one link in the email is easier to quickly click than two.
|
||||
You're receiving this email because of your account on #{Gitlab.config.gitlab.host}.
|
||||
If you'd like to receive fewer emails, you can adjust your notification settings.
|
||||
If you'd like to receive fewer emails, you can
|
||||
- if @sent_notification && @sent_notification.unsubscribable?
|
||||
= link_to "unsubscribe", unsubscribe_sent_notification_url(@sent_notification)
|
||||
from this thread or
|
||||
adjust your notification settings.
|
||||
|
||||
= email_action @target_url
|
||||
= email_action @target_url
|
||||
|
|
|
@ -5,12 +5,9 @@
|
|||
%a.close{href: "#", "data-dismiss" => "modal"} ×
|
||||
%h3.page-title New Wiki Page
|
||||
.modal-body
|
||||
= label_tag :new_wiki_path do
|
||||
%span Page slug
|
||||
= text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project)
|
||||
%p.hidden.text-danger{data: { error: "slug" }}
|
||||
The page slug is invalid. Please don't use characters other then: a-z 0-9 _ - and /
|
||||
%p.hint
|
||||
Please don't use spaces.
|
||||
.form-group
|
||||
= label_tag :new_wiki_path do
|
||||
%span Page slug
|
||||
= text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project)
|
||||
.form-actions
|
||||
= link_to 'Create Page', '#', class: 'build-new-wiki btn btn-create'
|
||||
|
|
|
@ -88,6 +88,12 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :sent_notifications, only: [], constraints: { id: /\h{32}/ } do
|
||||
member do
|
||||
get :unsubscribe
|
||||
end
|
||||
end
|
||||
|
||||
# Spam reports
|
||||
resources :abuse_reports, only: [:new, :create]
|
||||
|
||||
|
@ -513,7 +519,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
WIKI_SLUG_ID = { id: /[a-zA-Z.0-9_\-\/]+/ } unless defined? WIKI_SLUG_ID
|
||||
WIKI_SLUG_ID = { id: /\S+/ } unless defined? WIKI_SLUG_ID
|
||||
|
||||
scope do
|
||||
# Order matters to give priority to these matches
|
||||
|
|
|
@ -69,11 +69,6 @@ Feature: Project Wiki
|
|||
And I click on the "Pages" button
|
||||
Then I should see non-escaped link in the pages list
|
||||
|
||||
@javascript
|
||||
Scenario: Creating an invalid new page
|
||||
Given I create a New page with an invalid name
|
||||
Then I should see an error message
|
||||
|
||||
@javascript
|
||||
Scenario: Edit Wiki page that has a path
|
||||
Given I create a New page with paths
|
||||
|
|
|
@ -132,16 +132,6 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
|
|||
expect(current_path).to include 'one/two/three'
|
||||
end
|
||||
|
||||
step 'I create a New page with an invalid name' do
|
||||
click_on 'New Page'
|
||||
fill_in 'Page slug', with: 'invalid name'
|
||||
click_on 'Create Page'
|
||||
end
|
||||
|
||||
step 'I should see an error message' do
|
||||
expect(page).to have_content "The page slug is invalid"
|
||||
end
|
||||
|
||||
step 'I should see non-escaped link in the pages list' do
|
||||
expect(page).to have_xpath("//a[@href='/#{project.path_with_namespace}/wikis/one/two/three']")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
require 'banzai'
|
||||
require 'html/pipeline/filter'
|
||||
|
||||
module Banzai
|
||||
module Filter
|
||||
# HTML Filter for parsing Gollum's tags in HTML. It's only parses the
|
||||
# following tags:
|
||||
#
|
||||
# - Link to internal pages:
|
||||
#
|
||||
# * [[Bug Reports]]
|
||||
# * [[How to Contribute|Contributing]]
|
||||
#
|
||||
# - Link to external resources:
|
||||
#
|
||||
# * [[http://en.wikipedia.org/wiki/Git_(software)]]
|
||||
# * [[Git|http://en.wikipedia.org/wiki/Git_(software)]]
|
||||
#
|
||||
# - Link internal images, the special attributes will be ignored:
|
||||
#
|
||||
# * [[images/logo.png]]
|
||||
# * [[images/logo.png|alt=Logo]]
|
||||
#
|
||||
# - Link external images, the special attributes will be ignored:
|
||||
#
|
||||
# * [[http://example.com/images/logo.png]]
|
||||
# * [[http://example.com/images/logo.png|alt=Logo]]
|
||||
#
|
||||
# Based on Gollum::Filter::Tags
|
||||
#
|
||||
# Context options:
|
||||
# :project_wiki (required) - Current project wiki.
|
||||
#
|
||||
class GollumTagsFilter < HTML::Pipeline::Filter
|
||||
include ActionView::Helpers::TagHelper
|
||||
|
||||
# Pattern to match tags content that should be parsed in HTML.
|
||||
#
|
||||
# Gollum's tags have been made to resemble the tags of other markups,
|
||||
# especially MediaWiki. The basic syntax is:
|
||||
#
|
||||
# [[tag]]
|
||||
#
|
||||
# Some tags will accept attributes which are separated by pipe
|
||||
# symbols.Some attributes must precede the tag and some must follow it:
|
||||
#
|
||||
# [[prefix-attribute|tag]]
|
||||
# [[tag|suffix-attribute]]
|
||||
#
|
||||
# See https://github.com/gollum/gollum/wiki
|
||||
#
|
||||
# Rubular: http://rubular.com/r/7dQnE5CUCH
|
||||
TAGS_PATTERN = %r{\[\[(.+?)\]\]}
|
||||
|
||||
# Pattern to match allowed image extensions
|
||||
ALLOWED_IMAGE_EXTENSIONS = %r{.+(jpg|png|gif|svg|bmp)\z}i
|
||||
|
||||
def call
|
||||
search_text_nodes(doc).each do |node|
|
||||
content = node.content
|
||||
|
||||
next unless content.match(TAGS_PATTERN)
|
||||
|
||||
html = process_tag($1)
|
||||
|
||||
if html && html != node.content
|
||||
node.replace(html)
|
||||
end
|
||||
end
|
||||
|
||||
doc
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Process a single tag into its final HTML form.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
#
|
||||
# Returns the String HTML version of the tag.
|
||||
def process_tag(tag)
|
||||
parts = tag.split('|')
|
||||
|
||||
return if parts.size.zero?
|
||||
|
||||
process_image_tag(parts) || process_page_link_tag(parts)
|
||||
end
|
||||
|
||||
# Attempt to process the tag as an image tag.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
#
|
||||
# Returns the String HTML if the tag is a valid image tag or nil
|
||||
# if it is not.
|
||||
def process_image_tag(parts)
|
||||
content = parts[0].strip
|
||||
|
||||
return unless image?(content)
|
||||
|
||||
if url?(content)
|
||||
path = content
|
||||
elsif file = project_wiki.find_file(content)
|
||||
path = ::File.join project_wiki_base_path, file.path
|
||||
end
|
||||
|
||||
if path
|
||||
content_tag(:img, nil, src: path)
|
||||
end
|
||||
end
|
||||
|
||||
def image?(path)
|
||||
path =~ ALLOWED_IMAGE_EXTENSIONS
|
||||
end
|
||||
|
||||
def url?(path)
|
||||
path.start_with?(*%w(http https))
|
||||
end
|
||||
|
||||
# Attempt to process the tag as a page link tag.
|
||||
#
|
||||
# tag - The String tag contents (the stuff inside the double brackets).
|
||||
#
|
||||
# Returns the String HTML if the tag is a valid page link tag or nil
|
||||
# if it is not.
|
||||
def process_page_link_tag(parts)
|
||||
if parts.size == 1
|
||||
url = parts[0].strip
|
||||
else
|
||||
name, url = *parts.compact.map(&:strip)
|
||||
end
|
||||
|
||||
content_tag(:a, name || url, href: url)
|
||||
end
|
||||
|
||||
def project_wiki
|
||||
context[:project_wiki]
|
||||
end
|
||||
|
||||
def project_wiki_base_path
|
||||
project_wiki && project_wiki.wiki_base_path
|
||||
end
|
||||
|
||||
# Ensure that a :project_wiki key exists in context
|
||||
#
|
||||
# Note that while the key might exist, its value could be nil!
|
||||
def validate
|
||||
needs :project_wiki
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
require 'banzai'
|
||||
|
||||
module Banzai
|
||||
module Pipeline
|
||||
class WikiPipeline < FullPipeline
|
||||
def self.filters
|
||||
super.insert(1, Filter::GollumTagsFilter)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,8 @@
|
|||
module Gitlab
|
||||
module GithubImport
|
||||
class Importer
|
||||
include Gitlab::ShellAdapter
|
||||
|
||||
attr_reader :project, :client
|
||||
|
||||
def initialize(project)
|
||||
|
@ -12,10 +14,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def execute
|
||||
import_issues
|
||||
import_pull_requests
|
||||
|
||||
true
|
||||
import_issues && import_pull_requests && import_wiki
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -34,6 +33,10 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
false
|
||||
end
|
||||
|
||||
def import_pull_requests
|
||||
|
@ -48,6 +51,10 @@ module Gitlab
|
|||
import_comments_on_diff(pull_request.number, merge_request)
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
false
|
||||
end
|
||||
|
||||
def import_comments(issue_number, noteable)
|
||||
|
@ -66,6 +73,18 @@ module Gitlab
|
|||
noteable.notes.create!(comment.attributes)
|
||||
end
|
||||
end
|
||||
|
||||
def import_wiki
|
||||
unless project.wiki_enabled?
|
||||
wiki = WikiFormatter.new(project)
|
||||
gitlab_shell.import_repository(wiki.path_with_namespace, wiki.import_url)
|
||||
project.update_attribute(:wiki_enabled, true)
|
||||
end
|
||||
|
||||
true
|
||||
rescue Gitlab::Shell::Error
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,8 @@ module Gitlab
|
|||
visibility_level: repo.private ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
|
||||
import_type: "github",
|
||||
import_source: repo.full_name,
|
||||
import_url: repo.clone_url.sub("https://", "https://#{@session_data[:github_access_token]}@")
|
||||
import_url: repo.clone_url.sub("https://", "https://#{@session_data[:github_access_token]}@"),
|
||||
wiki_enabled: !repo.has_wiki? # If repo has wiki we'll import it later
|
||||
).execute
|
||||
|
||||
project.create_import_data(data: { "github_session" => session_data } )
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
module Gitlab
|
||||
module GithubImport
|
||||
class WikiFormatter
|
||||
attr_reader :project
|
||||
|
||||
def initialize(project)
|
||||
@project = project
|
||||
end
|
||||
|
||||
def path_with_namespace
|
||||
"#{project.path_with_namespace}.wiki"
|
||||
end
|
||||
|
||||
def import_url
|
||||
project.import_url.sub(/\.git\z/, ".wiki.git")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe SentNotificationsController, type: :controller do
|
||||
let(:user) { create(:user) }
|
||||
let(:issue) { create(:issue, author: user) }
|
||||
let(:sent_notification) { create(:sent_notification, noteable: issue) }
|
||||
|
||||
describe 'GET #unsubscribe' do
|
||||
it 'returns a 404 when calling without existing id' do
|
||||
get(:unsubscribe, id: '0' * 32)
|
||||
|
||||
expect(response.status).to be 404
|
||||
end
|
||||
|
||||
context 'calling with id' do
|
||||
it 'shows a flash message to the user' do
|
||||
get(:unsubscribe, id: sent_notification.reply_key)
|
||||
|
||||
expect(response.status).to be 302
|
||||
|
||||
expect(response).to redirect_to new_user_session_path
|
||||
expect(controller).to set_flash[:notice].to(/unsubscribed/).now
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -212,4 +212,11 @@ FactoryGirl.define do
|
|||
provider 'ldapmain'
|
||||
extern_uid 'my-ldap-id'
|
||||
end
|
||||
|
||||
factory :sent_notification do
|
||||
project
|
||||
recipient factory: :user
|
||||
noteable factory: :issue
|
||||
reply_key "0123456789abcdef" * 2
|
||||
end
|
||||
end
|
||||
|
|
|
@ -175,13 +175,15 @@ describe 'GitLab Markdown', feature: true do
|
|||
end
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
@feat = MarkdownFeature.new
|
||||
|
||||
# `markdown` helper expects a `@project` variable
|
||||
@project = @feat.project
|
||||
end
|
||||
|
||||
context 'default pipeline' do
|
||||
before(:all) do
|
||||
@feat = MarkdownFeature.new
|
||||
|
||||
# `markdown` helper expects a `@project` variable
|
||||
@project = @feat.project
|
||||
|
||||
@html = markdown(@feat.raw_markdown)
|
||||
end
|
||||
|
||||
|
@ -221,6 +223,57 @@ describe 'GitLab Markdown', feature: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'wiki pipeline' do
|
||||
before do
|
||||
@project_wiki = @feat.project_wiki
|
||||
|
||||
file = Gollum::File.new(@project_wiki.wiki)
|
||||
expect(file).to receive(:path).and_return('images/example.jpg')
|
||||
expect(@project_wiki).to receive(:find_file).with('images/example.jpg').and_return(file)
|
||||
|
||||
@html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki })
|
||||
end
|
||||
|
||||
it_behaves_like 'all pipelines'
|
||||
|
||||
it 'includes RelativeLinkFilter' do
|
||||
expect(doc).not_to parse_relative_links
|
||||
end
|
||||
|
||||
it 'includes EmojiFilter' do
|
||||
expect(doc).to parse_emoji
|
||||
end
|
||||
|
||||
it 'includes TableOfContentsFilter' do
|
||||
expect(doc).to create_header_links
|
||||
end
|
||||
|
||||
it 'includes AutolinkFilter' do
|
||||
expect(doc).to create_autolinks
|
||||
end
|
||||
|
||||
it 'includes all reference filters' do
|
||||
aggregate_failures do
|
||||
expect(doc).to reference_users
|
||||
expect(doc).to reference_issues
|
||||
expect(doc).to reference_merge_requests
|
||||
expect(doc).to reference_snippets
|
||||
expect(doc).to reference_commit_ranges
|
||||
expect(doc).to reference_commits
|
||||
expect(doc).to reference_labels
|
||||
expect(doc).to reference_milestones
|
||||
end
|
||||
end
|
||||
|
||||
it 'includes TaskListFilter' do
|
||||
expect(doc).to parse_task_lists
|
||||
end
|
||||
|
||||
it 'includes GollumTagsFilter' do
|
||||
expect(doc).to parse_gollum_tags
|
||||
end
|
||||
end
|
||||
|
||||
# Fake a `current_user` helper
|
||||
def current_user
|
||||
@feat.user
|
||||
|
|
|
@ -230,3 +230,12 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
|
|||
- [ ] Incomplete sub-task 2
|
||||
- [x] Complete sub-task 1
|
||||
- [X] Complete task 2
|
||||
|
||||
#### Gollum Tags
|
||||
|
||||
- [[linked-resource]]
|
||||
- [[link-text|linked-resource]]
|
||||
- [[http://example.com]]
|
||||
- [[link-text|http://example.com/pdfs/gollum.pdf]]
|
||||
- [[images/example.jpg]]
|
||||
- [[http://example.com/images/example.jpg]]
|
||||
|
|
|
@ -121,12 +121,13 @@ describe GitlabMarkdownHelper do
|
|||
before do
|
||||
@wiki = double('WikiPage')
|
||||
allow(@wiki).to receive(:content).and_return('wiki content')
|
||||
helper.instance_variable_set(:@project_wiki, @wiki)
|
||||
end
|
||||
|
||||
it "should use GitLab Flavored Markdown for markdown files" do
|
||||
it "should use Wiki pipeline for markdown files" do
|
||||
allow(@wiki).to receive(:format).and_return(:markdown)
|
||||
|
||||
expect(helper).to receive(:markdown).with('wiki content')
|
||||
expect(helper).to receive(:markdown).with('wiki content', pipeline: :wiki, project_wiki: @wiki)
|
||||
|
||||
helper.render_wiki_content(@wiki)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Filter::GollumTagsFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { double }
|
||||
let(:project_wiki) { ProjectWiki.new(project, user) }
|
||||
|
||||
describe 'validation' do
|
||||
it 'ensure that a :project_wiki key exists in context' do
|
||||
expect { filter("See [[images/image.jpg]]", {}) }.to raise_error ArgumentError, "Missing context keys for Banzai::Filter::GollumTagsFilter: :project_wiki"
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking internal images' do
|
||||
it 'creates img tag if image exists' do
|
||||
file = Gollum::File.new(project_wiki.wiki)
|
||||
expect(file).to receive(:path).and_return('images/image.jpg')
|
||||
expect(project_wiki).to receive(:find_file).with('images/image.jpg').and_return(file)
|
||||
|
||||
tag = '[[images/image.jpg]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('img')['src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg"
|
||||
end
|
||||
|
||||
it 'does not creates img tag if image does not exist' do
|
||||
expect(project_wiki).to receive(:find_file).with('images/image.jpg').and_return(nil)
|
||||
|
||||
tag = '[[images/image.jpg]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.css('img').size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking external images' do
|
||||
it 'creates img tag for valid URL' do
|
||||
tag = '[[http://example.com/image.jpg]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('img')['src']).to eq "http://example.com/image.jpg"
|
||||
end
|
||||
|
||||
it 'does not creates img tag for invalid URL' do
|
||||
tag = '[[http://example.com/image.pdf]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.css('img').size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking external resources' do
|
||||
it "the created link's text will be equal to the resource's text" do
|
||||
tag = '[[http://example.com]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'http://example.com'
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com'
|
||||
end
|
||||
|
||||
it "the created link's text will be link-text" do
|
||||
tag = '[[link-text|http://example.com/pdfs/gollum.pdf]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'link-text'
|
||||
expect(doc.at_css('a')['href']).to eq 'http://example.com/pdfs/gollum.pdf'
|
||||
end
|
||||
end
|
||||
|
||||
context 'linking internal resources' do
|
||||
it "the created link's text will be equal to the resource's text" do
|
||||
tag = '[[wiki-slug]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'wiki-slug'
|
||||
expect(doc.at_css('a')['href']).to eq 'wiki-slug'
|
||||
end
|
||||
|
||||
it "the created link's text will be link-text" do
|
||||
tag = '[[link-text|wiki-slug]]'
|
||||
doc = filter("See #{tag}", project_wiki: project_wiki)
|
||||
|
||||
expect(doc.at_css('a').text).to eq 'link-text'
|
||||
expect(doc.at_css('a')['href']).to eq 'wiki-slug'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GithubImport::WikiFormatter, lib: true do
|
||||
let(:project) do
|
||||
create(:project, namespace: create(:namespace, path: 'gitlabhq'),
|
||||
import_url: 'https://xxx@github.com/gitlabhq/sample.gitlabhq.git')
|
||||
end
|
||||
|
||||
subject(:wiki) { described_class.new(project)}
|
||||
|
||||
describe '#path_with_namespace' do
|
||||
it 'appends .wiki to project path' do
|
||||
expect(wiki.path_with_namespace).to eq 'gitlabhq/gitlabhq.wiki'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#import_url' do
|
||||
it 'returns URL of the wiki repository' do
|
||||
expect(wiki.import_url).to eq 'https://xxx@github.com/gitlabhq/sample.gitlabhq.wiki.git'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -104,6 +104,14 @@ describe Notify do
|
|||
it { is_expected.to have_body_text /View Commit/ }
|
||||
end
|
||||
|
||||
shared_examples 'an unsubscribeable thread' do
|
||||
it { is_expected.to have_body_text /unsubscribe/ }
|
||||
end
|
||||
|
||||
shared_examples "a user cannot unsubscribe through footer link" do
|
||||
it { is_expected.not_to have_body_text /unsubscribe/ }
|
||||
end
|
||||
|
||||
describe 'for new users, the email' do
|
||||
let(:example_site_path) { root_path }
|
||||
let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) }
|
||||
|
@ -115,6 +123,7 @@ describe Notify do
|
|||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like 'a new user email', new_user_address
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like 'a user cannot unsubscribe through footer link'
|
||||
|
||||
it 'contains the password text' do
|
||||
is_expected.to have_body_text /Click here to set your password/
|
||||
|
@ -134,7 +143,6 @@ describe Notify do
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'for users that signed up, the email' do
|
||||
let(:example_site_path) { root_path }
|
||||
let(:new_user) { create(:user, email: new_user_address, password: "securePassword") }
|
||||
|
@ -144,6 +152,7 @@ describe Notify do
|
|||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like 'a new user email', new_user_address
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like 'a user cannot unsubscribe through footer link'
|
||||
|
||||
it 'should not contain the new user\'s password' do
|
||||
is_expected.not_to have_body_text /password/
|
||||
|
@ -157,6 +166,7 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like 'a user cannot unsubscribe through footer link'
|
||||
|
||||
it 'is sent to the new user' do
|
||||
is_expected.to deliver_to key.user.email
|
||||
|
@ -181,6 +191,7 @@ describe Notify do
|
|||
subject { Notify.new_email_email(email.id) }
|
||||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like 'a user cannot unsubscribe through footer link'
|
||||
|
||||
it 'is sent to the new user' do
|
||||
is_expected.to deliver_to email.user.email
|
||||
|
@ -227,6 +238,7 @@ describe Notify do
|
|||
it_behaves_like 'an assignee email'
|
||||
it_behaves_like 'an email starting a new thread', 'issue'
|
||||
it_behaves_like 'it should show Gmail Actions View Issue link'
|
||||
it_behaves_like 'an unsubscribeable thread'
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/
|
||||
|
@ -253,6 +265,7 @@ describe Notify do
|
|||
it_behaves_like 'a multiple recipients email'
|
||||
it_behaves_like 'an answer to an existing thread', 'issue'
|
||||
it_behaves_like 'it should show Gmail Actions View Issue link'
|
||||
it_behaves_like "an unsubscribeable thread"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -283,6 +296,7 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'an answer to an existing thread', 'issue'
|
||||
it_behaves_like 'it should show Gmail Actions View Issue link'
|
||||
it_behaves_like 'an unsubscribeable thread'
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -319,6 +333,7 @@ describe Notify do
|
|||
it_behaves_like 'an assignee email'
|
||||
it_behaves_like 'an email starting a new thread', 'merge_request'
|
||||
it_behaves_like 'it should show Gmail Actions View Merge request link'
|
||||
it_behaves_like "an unsubscribeable thread"
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
|
||||
|
@ -345,6 +360,7 @@ describe Notify do
|
|||
subject { Notify.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) }
|
||||
|
||||
it_behaves_like 'it should show Gmail Actions View Merge request link'
|
||||
it_behaves_like "an unsubscribeable thread"
|
||||
|
||||
it 'contains the description' do
|
||||
is_expected.to have_body_text /#{merge_request_with_description.description}/
|
||||
|
@ -357,6 +373,7 @@ describe Notify do
|
|||
it_behaves_like 'a multiple recipients email'
|
||||
it_behaves_like 'an answer to an existing thread', 'merge_request'
|
||||
it_behaves_like 'it should show Gmail Actions View Merge request link'
|
||||
it_behaves_like "an unsubscribeable thread"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -387,6 +404,7 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'an answer to an existing thread', 'merge_request'
|
||||
it_behaves_like 'it should show Gmail Actions View Merge request link'
|
||||
it_behaves_like "an unsubscribeable thread"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -417,6 +435,7 @@ describe Notify do
|
|||
it_behaves_like 'a multiple recipients email'
|
||||
it_behaves_like 'an answer to an existing thread', 'merge_request'
|
||||
it_behaves_like 'it should show Gmail Actions View Merge request link'
|
||||
it_behaves_like "an unsubscribeable thread"
|
||||
|
||||
it 'is sent as the merge author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -446,6 +465,7 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /Project was moved/
|
||||
|
@ -468,6 +488,7 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /Access to project was granted/
|
||||
|
@ -518,6 +539,7 @@ describe Notify do
|
|||
it_behaves_like 'a note email'
|
||||
it_behaves_like 'an answer to an existing thread', 'commit'
|
||||
it_behaves_like 'it should show Gmail Actions View Commit link'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/
|
||||
|
@ -538,6 +560,7 @@ describe Notify do
|
|||
it_behaves_like 'a note email'
|
||||
it_behaves_like 'an answer to an existing thread', 'merge_request'
|
||||
it_behaves_like 'it should show Gmail Actions View Merge request link'
|
||||
it_behaves_like 'an unsubscribeable thread'
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
|
||||
|
@ -558,6 +581,7 @@ describe Notify do
|
|||
it_behaves_like 'a note email'
|
||||
it_behaves_like 'an answer to an existing thread', 'issue'
|
||||
it_behaves_like 'it should show Gmail Actions View Issue link'
|
||||
it_behaves_like 'an unsubscribeable thread'
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /#{issue.title} \(##{issue.iid}\)/
|
||||
|
@ -579,6 +603,7 @@ describe Notify do
|
|||
|
||||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'has the correct subject' do
|
||||
is_expected.to have_subject /Access to group was granted/
|
||||
|
@ -607,6 +632,7 @@ describe Notify do
|
|||
subject { ActionMailer::Base.deliveries.last }
|
||||
|
||||
it_behaves_like 'an email sent from GitLab'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent to the new user' do
|
||||
is_expected.to deliver_to 'new-email@mail.com'
|
||||
|
@ -629,6 +655,7 @@ describe Notify do
|
|||
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :create) }
|
||||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -657,6 +684,7 @@ describe Notify do
|
|||
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :create) }
|
||||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -684,6 +712,7 @@ describe Notify do
|
|||
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :delete) }
|
||||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -707,6 +736,7 @@ describe Notify do
|
|||
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) }
|
||||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -734,6 +764,7 @@ describe Notify do
|
|||
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, send_from_committer_email: send_from_committer_email) }
|
||||
|
||||
it_behaves_like 'it should not have Gmail Actions links'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
@ -839,6 +870,7 @@ describe Notify do
|
|||
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare) }
|
||||
|
||||
it_behaves_like 'it should show Gmail Actions View Commit link'
|
||||
it_behaves_like "a user cannot unsubscribe through footer link"
|
||||
|
||||
it 'is sent as the author' do
|
||||
sender = subject.header[:from].addrs[0]
|
||||
|
|
|
@ -36,6 +36,13 @@ describe ProjectWiki, models: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#wiki_base_path" do
|
||||
it "returns the wiki base path" do
|
||||
wiki_base_path = "/#{project.path_with_namespace}/wikis"
|
||||
expect(subject.wiki_base_path).to eq(wiki_base_path)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#wiki" do
|
||||
it "contains a Gollum::Wiki instance" do
|
||||
expect(subject.wiki).to be_a Gollum::Wiki
|
||||
|
|
|
@ -28,6 +28,10 @@ class MarkdownFeature
|
|||
end
|
||||
end
|
||||
|
||||
def project_wiki
|
||||
@project_wiki ||= ProjectWiki.new(project, user)
|
||||
end
|
||||
|
||||
def issue
|
||||
@issue ||= create(:issue, project: project)
|
||||
end
|
||||
|
|
|
@ -66,6 +66,24 @@ module MarkdownMatchers
|
|||
end
|
||||
end
|
||||
|
||||
# GollumTagsFilter
|
||||
matcher :parse_gollum_tags do
|
||||
def have_image(src)
|
||||
have_css("img[src$='#{src}']")
|
||||
end
|
||||
|
||||
set_default_markdown_messages
|
||||
|
||||
match do |actual|
|
||||
expect(actual).to have_link('linked-resource', href: 'linked-resource')
|
||||
expect(actual).to have_link('link-text', href: 'linked-resource')
|
||||
expect(actual).to have_link('http://example.com', href: 'http://example.com')
|
||||
expect(actual).to have_link('link-text', href: 'http://example.com/pdfs/gollum.pdf')
|
||||
expect(actual).to have_image('/gitlabhq/wikis/images/example.jpg')
|
||||
expect(actual).to have_image('http://example.com/images/example.jpg')
|
||||
end
|
||||
end
|
||||
|
||||
# UserReferenceFilter
|
||||
matcher :reference_users do
|
||||
set_default_markdown_messages
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue