Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

Commit

Permalink
Merge branch 'release-0.4'
Browse files Browse the repository at this point in the history
**New Features**:
- Project file management

**Fixes**:
- Form elements with inherited styling will correctly show up as invalid
if an error occurs on the input element's attribute
  • Loading branch information
FinnWoelm committed Sep 13, 2017
2 parents df5c79b + fa9ba5a commit d91223a
Show file tree
Hide file tree
Showing 47 changed files with 2,356 additions and 156 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# CHANGELOG

## v0.4 (September 13, 2017)

**New Features**:
- Project file management

**Fixes**:
- Form elements with inherited styling will correctly show up as invalid if an
error occurs on the input element's attribute


## v0.3 (August 13, 2017)

**New Features**:
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/controllers/all.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// CSS styles meant to apply to specific controllers

@import 'errors';
@import 'files';
@import 'profiles';
@import 'static';
8 changes: 8 additions & 0 deletions app/assets/stylesheets/controllers/files.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Styling for FilesController

// Add spacing around each file entry on index page
.file-wrapper {
padding: 8px 0;
h5 { margin: 4px 0; }
p { margin: 4px 0; }
}
35 changes: 25 additions & 10 deletions app/assets/stylesheets/shared/forms.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
// Styling for forms

// Input elements
.input-field input + label {
transform: translateY(-14px) scale(.8);
transform-origin: 0 0;
.input-field {
input,
textarea {
+ label {
transform: translateY(-14px) scale(.8);
transform-origin: 0 0;
}
}

// Multiple input fields in a single line (used for prefix/suffix)
&.group {
display: flex;
flex-direction: row;
}
}

// scss-lint:disable QualifyingElement
Expand All @@ -12,13 +23,16 @@ input[type='text'] {
// Input elements that inherit styling from their parent
&.inherit {
// scss-lint:disable ImportantRule
border-color: currentColor !important;
box-shadow: none !important;
font-size: inherit;
height: auto;
line-height: inherit;
margin: 0;
padding: 0;

&:not(.invalid) {
border-color: currentColor !important;
}
}
}
// scss-lint:enable QualifyingElement
Expand All @@ -31,12 +45,6 @@ input[type='text'] {
opacity: .5;
}

// Multiple input fields in a single line (used for prefix/suffix)
.input-field.group {
display: flex;
flex-direction: row;
}

// scss-lint:disable PropertyCount
.mock-input {
background-color: transparent;
Expand All @@ -60,3 +68,10 @@ input[type='text'] {
}
}
// scss-lint:enable PropertyCount

// Adapt materialize textarea to work decently well without JS
.materialize-textarea.noscript {
height: auto;
overflow-y: scroll;
resize: vertical;
}
8 changes: 8 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :exception

before_action :configure_permitted_parameters, if: :devise_controller?
before_action :set_default_request_format

# override sign in redirect (Devise)
def after_sign_in_path_for(resource)
Expand Down Expand Up @@ -36,4 +37,11 @@ def configure_permitted_parameters
end
end
# rubocop:enable Metrics/MethodLength

# Override the request format to prevent Rails from implying the format from
# the URL. This is necessary because file names can end in .json or. xml or
# other endings that are normally parsed by Rails.
def set_default_request_format
request.format = :html unless params[:format]
end
end
96 changes: 96 additions & 0 deletions app/controllers/files_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true

# Controller for project files
class FilesController < ApplicationController
before_action :authenticate_account!, except: %i[index show]
before_action :set_project
before_action :build_file, only: %i[new create]
before_action :set_file, except: %i[index new create]
before_action :authorize_action, except: %i[index show]

def index
# sort files in alphabetical order (case insensitive) but always put
# Overview file first
@files = @project
.files
.sort_by { |f| [f.name == 'Overview' ? 0 : 1, f.name.downcase] }
@user_can_add_file = can? :new, @project.files.build, @project
end

def new; end

def create
if @file.update(file_params(%i[content name]))
redirect_to [@project.owner, @project, @file],
notice: 'File successfully created.'
else
render :new
end
end

def show; end

def edit_content; end

def update_content
if @file.update(file_params(:content))
redirect_to [@project.owner, @project, @file],
notice: 'File successfully updated.'
else
render :edit_content
end
end

def edit_name; end

def update_name
if @file.update(file_params(:name))
redirect_to [@project.owner, @project, @file],
notice: 'File successfully updated.'
else
render :edit_name
end
end

def delete; end

def destroy
@file.revision_author = current_user
@file.revision_summary = params[:version_control_file][:revision_summary]
if @file.destroy
redirect_to profile_project_files_path(@project.owner, @project),
notice: 'File successfully deleted.'
else
render :delete
end
end

private

rescue_from CanCan::AccessDenied do |exception|
redirect_to [@project.owner, @project, @file],
alert: exception.message
end

def authorize_action
authorize! params[:action].to_sym, @file, @project
end

def set_project
@project = Project.find(params[:profile_handle], params[:project_slug])
end

def build_file
@file = @project.files.build
end

def set_file
@file = @project.files.find params[:name]
end

def file_params(permitted_attributes = [])
params.require(:version_control_file)
.permit(*permitted_attributes, :revision_summary)
.merge(revision_author: current_user)
end
end
29 changes: 29 additions & 0 deletions app/helpers/file_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

# Define helpers needed in file files
module FileHelper
# rubocop:disable Metrics/MethodLength
def authorized_actions_for_project_file(file, project)
authorized_actions = []
if can? :edit_content, file, project
authorized_actions.push(
name: :edit,
link: edit_profile_project_file_path(project.owner, project, file)
)
end
if can? :edit_name, file, project
authorized_actions.push(
name: :rename,
link: rename_profile_project_file_path(project.owner, project, file)
)
end
if can? :delete, file, project
authorized_actions.push(
name: :delete,
link: delete_profile_project_file_path(project.owner, project, file)
)
end
authorized_actions
end
# rubocop:enable Metrics/MethodLength
end
17 changes: 17 additions & 0 deletions app/helpers/layout_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,21 @@ def navigation_links
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/LineLength

# Used to achieve nested layouts without content_for. This helper relies on
# Rails internals, so beware that it make break with future major versions
# of Rails. Inspired by http://stackoverflow.com/a/18214036
#
# Usage: For example, suppose "child" layout extends "parent" layout.
# Use <%= yield %> as you would with non-nested layouts, as usual. Then on
# the very last line of layouts/child.html.erb, include this:
#
# <% parent_layout "parent" %>
#
# Credits: https://gist.github.com/mattbrictson/9240548
def parent_layout(layout)
@view_flow.set :layout, output_buffer
output = render(file: "layouts/#{layout}")
self.output_buffer = ActionView::OutputBuffer.new(output)
end
end
15 changes: 14 additions & 1 deletion app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class Ability
include CanCan::Ability

# rubocop:disable Metrics/MethodLength
def initialize(user)
return unless user

Expand All @@ -12,8 +13,19 @@ def initialize(user)

# Users can edit the projects of profiles that they can manage
can %i[edit update destroy], Project do |project|
can? :manaage, project.owner
can? :manage, project.owner
end

can %i[new create edit_content update_content],
VersionControl::File do |_file, project|
can? :edit, project
end

can %i[edit_name update_name delete delete destroy],
VersionControl::File do |file, project|
can?(:edit, project) && (file.name_was != 'Overview')
end

# Define abilities for the passed in user here. For example:
#
# user ||= User.new # guest user (not logged in)
Expand Down Expand Up @@ -41,4 +53,5 @@ def initialize(user)
# See the wiki for details:
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
end
# rubocop:enable Metrics/MethodLength
end
10 changes: 6 additions & 4 deletions app/models/concerns/version_control.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ module VersionControl
after_create do
begin
create_repository
files.create('Overview',
'Welcome to my new project!',
'Initial Contribution',
owner)
files.create(
name: 'Overview',
content: 'Welcome to my new project!',
revision_summary: 'Initial Contribution',
revision_author: owner
)
rescue
# Do not persist object if any errors occur while creating repository
raise ActiveRecord::Rollback
Expand Down
Loading

0 comments on commit d91223a

Please sign in to comment.