diff --git a/app/controllers/timelines_controller.rb b/app/controllers/timelines_controller.rb new file mode 100644 index 00000000..bcf2f7e7 --- /dev/null +++ b/app/controllers/timelines_controller.rb @@ -0,0 +1,101 @@ +class TimelinesController < ApplicationController + before_action :set_timeline, only: [:show, :edit, :update, :destroy] + + before_action :set_navbar_color + before_action :set_navbar_actions + before_action :set_sidenav_expansion + + # GET /timelines + def index + @timelines = current_user.timelines + end + + # GET /timelines/1 + def show + end + + # GET /timelines/new + def new + @timeline = Timeline.new + end + + # GET /timelines/1/edit + def edit + end + + # POST /timelines + def create + @timeline = Timeline.new(timeline_params) + + if @timeline.save + redirect_to @timeline, notice: 'Timeline was successfully created.' + else + render :new + end + end + + # PATCH/PUT /timelines/1 + def update + if @timeline.update(timeline_params) + redirect_to @timeline, notice: 'Timeline was successfully updated.' + else + render :edit + end + end + + # DELETE /timelines/1 + def destroy + @timeline.destroy + redirect_to timelines_url, notice: 'Timeline was successfully destroyed.' + end + + private + + # Use callbacks to share common setup or constraints between actions. + def set_timeline + @timeline = Timeline.find(params[:id]) + end + + # Only allow a trusted parameter "white list" through. + def timeline_params + params.fetch(:timeline, {}) + end + + def set_navbar_color + @navbar_color = Timeline.hex_color.presence || '#2196F3' + end + + def set_navbar_actions + # content_type = @content_type_class || content_type_from_controller(self.class) + # @navbar_actions = [] + + # return if [AttributeCategory, AttributeField].include?(content_type) + + # if user_signed_in? + # if @current_user_content + # @navbar_actions << { + # label: "Your #{view_context.pluralize @current_user_content.fetch(content_type.name, []).count, content_type.name.downcase}", + # href: main_app.polymorphic_path(content_type) + # } + # end + + # @navbar_actions << { + # label: "New #{content_type.name.downcase}", + # href: main_app.new_polymorphic_path(content_type), + # class: 'right' + # } + # end + + # discussions_link = ForumsLinkbuilderService.worldbuilding_url(content_type) + # if discussions_link.present? + # @navbar_actions << { + # label: 'Discussions', + # href: discussions_link + # } + # end + end + + def set_sidenav_expansion + @sidenav_expansion = 'writing' + end +end diff --git a/app/helpers/timelines_helper.rb b/app/helpers/timelines_helper.rb new file mode 100644 index 00000000..1f1a4f07 --- /dev/null +++ b/app/helpers/timelines_helper.rb @@ -0,0 +1,2 @@ +module TimelinesHelper +end diff --git a/app/models/concerns/has_content.rb b/app/models/concerns/has_content.rb index 689a5ad0..7448fb6b 100644 --- a/app/models/concerns/has_content.rb +++ b/app/models/concerns/has_content.rb @@ -10,6 +10,7 @@ module HasContent #has_many :characters, :locations, etc has_many content_type_sym, dependent: :destroy end + has_many :timelines has_many :attribute_fields has_many :attribute_categories diff --git a/app/models/page_types/universe.rb b/app/models/page_types/universe.rb index bb20c232..ca6d4884 100644 --- a/app/models/page_types/universe.rb +++ b/app/models/page_types/universe.rb @@ -15,7 +15,7 @@ class Universe < ApplicationRecord include Authority::Abilities self.authorizer_name = 'UniverseCoreContentAuthorizer' - validates :name, presence: true + validates :name, presence: true validates :user_id, presence: true belongs_to :user diff --git a/app/models/timeline.rb b/app/models/timeline.rb index 608e663b..083fc77b 100644 --- a/app/models/timeline.rb +++ b/app/models/timeline.rb @@ -1,4 +1,32 @@ class Timeline < ApplicationRecord + acts_as_paranoid + + include IsContentPage + include Authority::Abilities + self.authorizer_name = 'ExtendedContentAuthorizer' + belongs_to :universe belongs_to :user + + validates :user_id, presence: true + + def self.content_name + 'timeline' + end + + def description + 'A timeline' + end + + def self.color + 'green' + end + + def self.hex_color + '#4CAF50' + end + + def self.icon + 'timeline' + end end diff --git a/app/views/layouts/_sidenav.html.erb b/app/views/layouts/_sidenav.html.erb index 67666fb3..c398c6ed 100644 --- a/app/views/layouts/_sidenav.html.erb +++ b/app/views/layouts/_sidenav.html.erb @@ -96,12 +96,6 @@
+ Only showing timelines + in the <%= link_to @universe_scope.name, @universe_scope, class: Universe.color + '-text' %> universe. + <%= link_to( + "See timelines from all universes.", + '?universe=all', + class: Timeline.color + '-text') + %> +
+ <% end %> + +<% elsif @timelines.empty? %> + ++ <%= t("content_descriptions.timelines") %> +
+ + <% if current_user.can_create?(Timeline) || PermissionService.user_has_active_promotion_for_this_content_type(user: current_user, content_type: 'Timeline') %> + <%= link_to "Create your first timeline", new_timeline_path(), class: "btn-large #{Timeline.color} darken-1" %> + <% else %> + <%= link_to "Upgrade to Premium to create your first timeline", subscription_path %> + <% end %> + ++ <% 5.times { %><%= Timeline.icon %> <%}%> +
++ You're currently focused on the + <%= link_to @universe_scope.name, @universe_scope, class: Universe.color + '-text' %> + universe and only seeing timelines in that + universe. +
++ You can change what universe you're focused on by selecting a different one in the sidebar. +
+<%= notice %>
+ +<%= link_to 'Edit', edit_timeline_path(@timeline) %> | +<%= link_to 'Back', timelines_path %> diff --git a/config/routes.rb b/config/routes.rb index 69b54c8b..d03a97de 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -73,7 +73,7 @@ Rails.application.routes.draw do get '/scratchpad', to: 'main#notes', as: :notes - # Legacy routes: left intact so /my/documents/X URLs continue to work for everyone's bookmarks + # Legacy route: left intact so /my/documents/X URLs continue to work for everyone's bookmarks resources :documents # Billing @@ -184,6 +184,7 @@ end get '/tagged/:slug', action: :index, on: :collection, as: :page_tag end end + resources :timelines # Content attributes put '/content/sort', to: 'content#api_sort' @@ -195,9 +196,6 @@ end # Attributes get ':content_type/attributes', to: 'content#attributes', as: :attribute_customization - - # Coming Soon TM - get '/plots', to: 'main#comingsoon' end get 'search/', to: 'search#results' diff --git a/test/controllers/timelines_controller_test.rb b/test/controllers/timelines_controller_test.rb new file mode 100644 index 00000000..edad3334 --- /dev/null +++ b/test/controllers/timelines_controller_test.rb @@ -0,0 +1,48 @@ +require 'test_helper' + +class TimelinesControllerTest < ActionDispatch::IntegrationTest + setup do + @timeline = timelines(:one) + end + + test "should get index" do + get timelines_url + assert_response :success + end + + test "should get new" do + get new_timeline_url + assert_response :success + end + + test "should create timeline" do + assert_difference('Timeline.count') do + post timelines_url, params: { timeline: { } } + end + + assert_redirected_to timeline_url(Timeline.last) + end + + test "should show timeline" do + get timeline_url(@timeline) + assert_response :success + end + + test "should get edit" do + get edit_timeline_url(@timeline) + assert_response :success + end + + test "should update timeline" do + patch timeline_url(@timeline), params: { timeline: { } } + assert_redirected_to timeline_url(@timeline) + end + + test "should destroy timeline" do + assert_difference('Timeline.count', -1) do + delete timeline_url(@timeline) + end + + assert_redirected_to timelines_url + end +end diff --git a/test/system/timelines_test.rb b/test/system/timelines_test.rb new file mode 100644 index 00000000..32305373 --- /dev/null +++ b/test/system/timelines_test.rb @@ -0,0 +1,41 @@ +require "application_system_test_case" + +class TimelinesTest < ApplicationSystemTestCase + setup do + @timeline = timelines(:one) + end + + test "visiting the index" do + visit timelines_url + assert_selector "h1", text: "Timelines" + end + + test "creating a Timeline" do + visit timelines_url + click_on "New Timeline" + + click_on "Create Timeline" + + assert_text "Timeline was successfully created" + click_on "Back" + end + + test "updating a Timeline" do + visit timelines_url + click_on "Edit", match: :first + + click_on "Update Timeline" + + assert_text "Timeline was successfully updated" + click_on "Back" + end + + test "destroying a Timeline" do + visit timelines_url + page.accept_confirm do + click_on "Destroy", match: :first + end + + assert_text "Timeline was successfully destroyed" + end +end