diff --git a/Gemfile b/Gemfile index 2be3da5..807cce6 100644 --- a/Gemfile +++ b/Gemfile @@ -14,6 +14,9 @@ gem 'coffee-rails', '~> 4.1.0' # Integrate Paperclip into Mongoid. gem 'mongoid-paperclip' +# Markdown rendering +gem 'redcarpet' + # Stripe integration gem 'stripe' diff --git a/Gemfile.lock b/Gemfile.lock index 5f4332e..194156d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -260,6 +260,7 @@ GEM rb-inotify (0.9.10) ffi (>= 0.5.0, < 2) rdoc (4.3.0) + redcarpet (3.4.0) remotipart (1.3.1) responders (2.4.0) actionpack (>= 4.2.0, < 5.3) @@ -380,6 +381,7 @@ DEPENDENCIES rails-i18n rails_12factor rails_admin + redcarpet roadie-rails (~> 1.0) route_translator rspec-rails (~> 3.0) diff --git a/app/assets/javascripts/greendays.coffee b/app/assets/javascripts/greendays.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/greendays.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/greendays.sass b/app/assets/stylesheets/greendays.sass new file mode 100644 index 0000000..1c4a4b6 --- /dev/null +++ b/app/assets/stylesheets/greendays.sass @@ -0,0 +1,11 @@ +// Place all the styles related to the Greendays controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + +.well > h2 + margin-top: 0px + +#map + width: 100% + height: 300px + margin-bottom: 12px \ No newline at end of file diff --git a/app/assets/stylesheets/nav.sass b/app/assets/stylesheets/nav.sass index 4784233..a2549fe 100644 --- a/app/assets/stylesheets/nav.sass +++ b/app/assets/stylesheets/nav.sass @@ -23,8 +23,12 @@ nav#mainnav li font-size: 12pt - + li.selected background-color: $brand-success a color: white + + #greendays + margin-bottom: 12px + border: 1px solid $brand-success \ No newline at end of file diff --git a/app/assets/stylesheets/scaffolds.scss b/app/assets/stylesheets/scaffolds.scss new file mode 100644 index 0000000..4932c1f --- /dev/null +++ b/app/assets/stylesheets/scaffolds.scss @@ -0,0 +1,30 @@ +.field_with_errors { + padding: 2px; + background-color: red; + display: table; +} + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px; + padding-bottom: 0; + margin-bottom: 20px; + background-color: #f0f0f0; + + h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + margin-bottom: 0px; + background-color: #c00; + color: #fff; + } + + ul li { + font-size: 12px; + list-style: square; + } +} diff --git a/app/controllers/greendays_controller.rb b/app/controllers/greendays_controller.rb new file mode 100644 index 0000000..b49e929 --- /dev/null +++ b/app/controllers/greendays_controller.rb @@ -0,0 +1,65 @@ +class GreendaysController < ApplicationController + before_action :only_admin, except: [:index, :show] + before_action :set_greenday, only: [:show, :edit, :update, :destroy] + + def index + @greendays = Greenday.all.sort(title: 1) + end + + def new + @greenday = Greenday.new + end + + def edit; end + + def create + @greenday = Greenday.new(greenday_params) + + respond_to do |format| + if @greenday.save + format.html { redirect_to greendays_path, success: 'Greenday was successfully created.' } + format.json { render :show, status: :created, location: @greenday } + else + format.html { render :new } + format.json { render json: @greenday.errors, status: :unprocessable_entity } + end + end + end + + def update + respond_to do |format| + if @greenday.update(greenday_params) + format.html { redirect_to greendays_path, notice: 'Greenday was successfully updated.' } + format.json { render :show, status: :ok, location: @greenday } + else + format.html { render :edit } + format.json { render json: @greenday.errors, status: :unprocessable_entity } + end + end + end + + def destroy + @greenday.destroy + respond_to do |format| + format.html { redirect_to greendays_path, notice: 'Greenday was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + + # Use callbacks to share common setup or constraints between actions. + def set_greenday + @greenday = Greenday.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def greenday_params + params.require(:greenday).permit(:title, :address, :homepage, :description, :logo, :delete_logo) + end + + def only_admin + return true if current_supporter && current_supporter.admin? + raise ActionController::RoutingError, 'Not Found' + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 63f80ea..1c47532 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -3,4 +3,13 @@ module ApplicationHelper content_for :title, strip_tags(page_title.to_s) page_title end + + def markdown(content) + @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, space_after_headers: true) + @markdown.render(content) + end + + def admin? + current_supporter && current_supporter.admin? + end end diff --git a/app/models/greenday.rb b/app/models/greenday.rb new file mode 100644 index 0000000..197616e --- /dev/null +++ b/app/models/greenday.rb @@ -0,0 +1,43 @@ +class Greenday + include Mongoid::Document + include Mongoid::Timestamps + include Geocoder::Model::Mongoid + include Mongoid::Paperclip + + before_save :delete_logo? + + has_mongoid_attached_file :logo, + path: ':attachment/:id/:style.:extension', + styles: { + original: ['1920x1680>', :jpg], + small: ['100x100#', :jpg], + medium: ['250x250', :jpg], + large: ['500x500>', :jpg] + }, + convert_options: { all: '-background white -flatten +matte' } + + field :title, type: String + field :address, type: String + field :homepage, type: String + field :description, type: String + field :coordinates, type: Array + + geocoded_by :address + after_validation :geocode # auto-fetch coordinates + + validates :title, presence: true + validates :address, presence: true + validates_attachment_content_type :logo, content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'] + + def delete_logo + @delete_logo ||= '0' + end + + attr_writer :delete_logo + + private + + def delete_logo? + logo.clear if @delete_logo == '1' + end +end diff --git a/app/views/greendays/_form.html.slim b/app/views/greendays/_form.html.slim new file mode 100644 index 0000000..a070085 --- /dev/null +++ b/app/views/greendays/_form.html.slim @@ -0,0 +1,14 @@ += simple_form_for(@greenday) do |f| + = f.error_notification + + .form-inputs + = f.input :title + = f.input :address, as: :text + = f.input :homepage + = f.input :description, as: :text + = f.input :logo, as: :file, required: false + = image_tag f.object.logo.url(:original), alt: '', class: 'img-responsive' + = f.input :delete_logo, as: :boolean + + .form-actions + = f.button :submit, 'Shop speichern' diff --git a/app/views/greendays/_greenday.json.jbuilder b/app/views/greendays/_greenday.json.jbuilder new file mode 100644 index 0000000..d741703 --- /dev/null +++ b/app/views/greendays/_greenday.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! greenday, :id, :title, :address, :coordinates, :homepage, :logo, :description, :created_at, :updated_at +json.url greenday_url(greenday, format: :json) diff --git a/app/views/greendays/edit.html.slim b/app/views/greendays/edit.html.slim new file mode 100644 index 0000000..007d026 --- /dev/null +++ b/app/views/greendays/edit.html.slim @@ -0,0 +1,8 @@ +h1 Editing greenday + +== render 'form' + += link_to 'Show', @greenday +' | += link_to 'Back', greendays_path + diff --git a/app/views/greendays/index.html.slim b/app/views/greendays/index.html.slim new file mode 100644 index 0000000..04b512b --- /dev/null +++ b/app/views/greendays/index.html.slim @@ -0,0 +1,68 @@ + +h1.sr-only = title 'Gründonnerstag' +#map += link_to 'Neun Shop erfassen', new_greenday_path if admin? + +.row + - @greendays.each do |greenday| + .col-xs-12.col-sm-6.col-lg-4 + .well + h2 = greenday.title + - if greenday.logo + = image_tag greenday.logo.url(:original), alt: '', class: 'img-responsive' + address = simple_format(greenday.address) + - if greenday.homepage + = link_to(greenday.homepage, greenday.homepage, target: "_blank") + p = markdown(greenday.description).html_safe + + - if admin? + = link_to 'Bearbeiten', edit_greenday_path(greenday) + |   + = link_to 'Löschen', greenday, data: { confirm: 'Are you sure?' }, method: :delete + +javascript: + function initMap() { + + var map = new google.maps.Map(document.getElementById('map'), { + zoom: 8, center: {lat: 47.242, lng: 8.133}, + }); + + var greendays_url = "#{greendays_url(format: :json)}" + + var infowindow = new google.maps.InfoWindow({ + content: '', + maxWidth: 200 + }); + + + $.getJSON(greendays_url, function(json) { + $.each(json, function(key, data) { + var marker = new google.maps.Marker({ + position: {lat: data.coordinates[1], lng: data.coordinates[0] }, + map: map, + title: data.title + }); + + marker.addListener('click', function() { + infowindow.open(map, marker); + + var content = '' + data.title + '' + if(data.logo) { + content += '' + } + content += '
' + data.address.replace(/\n/g,"
") + if(data.homepage) { + content += '
' +data.homepage + '' + } + content += '
' + + if(data.description) { + content += '

' + data.description + '

' + } + infowindow.setContent(content); + }); + }); + }); + } + +script async="" defer="" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBbwMtGKDqf4i8x9-OVP1-H_QVAKp92h2M&callback=initMap&libraries=visualization" \ No newline at end of file diff --git a/app/views/greendays/index.json.jbuilder b/app/views/greendays/index.json.jbuilder new file mode 100644 index 0000000..30d440e --- /dev/null +++ b/app/views/greendays/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @greendays, partial: 'greendays/greenday', as: :greenday diff --git a/app/views/greendays/new.html.slim b/app/views/greendays/new.html.slim new file mode 100644 index 0000000..7e340d3 --- /dev/null +++ b/app/views/greendays/new.html.slim @@ -0,0 +1,5 @@ +h1 New greenday + +== render 'form' + += link_to 'Back', greendays_path diff --git a/config/navigation.rb b/config/navigation.rb index bd087ce..93b7e02 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -57,6 +57,8 @@ SimpleNavigation::Configuration.run do |navigation| # against the current URI. You may also use a proc, or the symbol :subpath. # + primary.item :greendays, 'Gründonnerstag', greendays_path + unless supporter_signed_in? primary.item :home, I18n.t('.shared.topnavigation.support'), "/#{I18n.locale}" end @@ -79,5 +81,7 @@ SimpleNavigation::Configuration.run do |navigation| else primary.item :home, I18n.t('.shared.topnavigation.sign_in'), new_supporter_session_path end + + end end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 5281711..1032f30 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :greendays devise_for :supporters root to: 'supporters#new' diff --git a/spec/models/greenday_spec.rb b/spec/models/greenday_spec.rb new file mode 100644 index 0000000..d8ba7a7 --- /dev/null +++ b/spec/models/greenday_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Greenday, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/greendays_spec.rb b/spec/requests/greendays_spec.rb new file mode 100644 index 0000000..282b151 --- /dev/null +++ b/spec/requests/greendays_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe "Greendays", type: :request do + describe "GET /greendays" do + it "works! (now write some real specs)" do + get greendays_path + expect(response).to have_http_status(200) + end + end +end diff --git a/spec/routing/greendays_routing_spec.rb b/spec/routing/greendays_routing_spec.rb new file mode 100644 index 0000000..6a08517 --- /dev/null +++ b/spec/routing/greendays_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe GreendaysController, type: :routing do + describe "routing" do + + it "routes to #index" do + expect(:get => "/greendays").to route_to("greendays#index") + end + + it "routes to #new" do + expect(:get => "/greendays/new").to route_to("greendays#new") + end + + it "routes to #show" do + expect(:get => "/greendays/1").to route_to("greendays#show", :id => "1") + end + + it "routes to #edit" do + expect(:get => "/greendays/1/edit").to route_to("greendays#edit", :id => "1") + end + + it "routes to #create" do + expect(:post => "/greendays").to route_to("greendays#create") + end + + it "routes to #update via PUT" do + expect(:put => "/greendays/1").to route_to("greendays#update", :id => "1") + end + + it "routes to #update via PATCH" do + expect(:patch => "/greendays/1").to route_to("greendays#update", :id => "1") + end + + it "routes to #destroy" do + expect(:delete => "/greendays/1").to route_to("greendays#destroy", :id => "1") + end + + end +end diff --git a/spec/views/greendays/edit.html.slim_spec.rb b/spec/views/greendays/edit.html.slim_spec.rb new file mode 100644 index 0000000..f5dc9d7 --- /dev/null +++ b/spec/views/greendays/edit.html.slim_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "greendays/edit", type: :view do + before(:each) do + @greenday = assign(:greenday, Greenday.create!( + :title => "MyString", + :address => "MyText", + :description => "MyText" + )) + end + + it "renders the edit greenday form" do + render + + assert_select "form[action=?][method=?]", greenday_path(@greenday), "post" do + + assert_select "input#greenday_title[name=?]", "greenday[title]" + + assert_select "textarea#greenday_address[name=?]", "greenday[address]" + + assert_select "textarea#greenday_description[name=?]", "greenday[description]" + end + end +end diff --git a/spec/views/greendays/index.html.slim_spec.rb b/spec/views/greendays/index.html.slim_spec.rb new file mode 100644 index 0000000..75e7e18 --- /dev/null +++ b/spec/views/greendays/index.html.slim_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe 'greendays/index' do + before(:each) do + assign(:greendays, [ + Greenday.create!( + title: 'Title', + address: 'Address', + description: 'MyText' + ), + Greenday.create!( + title: 'Title', + address: 'Address', + description: 'MyText' + ) + ]) + end + + it 'renders a list of greendays' do + render + assert_select 'h2', text: 'Title'.to_s, count: 2 + assert_select "address", :text => "Address".to_s, count: 2 + assert_select "p", :text => "MyText".to_s, count: 2 + end +end diff --git a/spec/views/greendays/new.html.slim_spec.rb b/spec/views/greendays/new.html.slim_spec.rb new file mode 100644 index 0000000..6c6130e --- /dev/null +++ b/spec/views/greendays/new.html.slim_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +RSpec.describe "greendays/new", type: :view do + before(:each) do + assign(:greenday, Greenday.new( + :title => "MyString", + :address => "MyText", + :description => "MyText" + )) + end + + it "renders new greenday form" do + render + + assert_select "form[action=?][method=?]", greendays_path, "post" do + + assert_select "input#greenday_title[name=?]", "greenday[title]" + + assert_select "textarea#greenday_address[name=?]", "greenday[address]" + + assert_select "textarea#greenday_description[name=?]", "greenday[description]" + end + end +end