krant 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +14 -0
  5. data/.travis.yml +16 -0
  6. data/Appraisals +14 -0
  7. data/CHANGELOG.md +7 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +192 -0
  12. data/Rakefile +4 -0
  13. data/admin/krant/broadcast_messages.rb +56 -0
  14. data/app/assets/stylesheets/krant/active_admin.scss +2 -0
  15. data/app/assets/stylesheets/krant/active_admin/broadcast_messages.scss +31 -0
  16. data/app/assets/stylesheets/krant/active_admin/news_list.scss +19 -0
  17. data/app/models/krant/broadcast_message.rb +10 -0
  18. data/app/models/krant/broadcast_message_translation.rb +6 -0
  19. data/app/models/krant/last_seen_state.rb +6 -0
  20. data/app/models/krant/news_item.rb +35 -0
  21. data/app/models/krant/translated_broadcast_message.rb +47 -0
  22. data/bin/console +14 -0
  23. data/bin/rails +12 -0
  24. data/bin/rspec +17 -0
  25. data/bin/setup +8 -0
  26. data/config/locales/de.yml +23 -0
  27. data/config/locales/en.yml +23 -0
  28. data/db/migrate/20171214095614_create_krant_broadcast_messages.rb +9 -0
  29. data/db/migrate/20171214095622_create_krant_broadcast_message_translations.rb +12 -0
  30. data/db/migrate/20171214175840_create_krant_news_items.rb +10 -0
  31. data/db/migrate/20171215080737_create_krant_last_seen_states.rb +10 -0
  32. data/gemfiles/rails_4.2_active_admin_1.0.0.pre4.gemfile +8 -0
  33. data/gemfiles/rails_4.2_active_admin_1.0.gemfile +8 -0
  34. data/gemfiles/rails_4.2_active_admin_1.1.gemfile +8 -0
  35. data/krant.gemspec +38 -0
  36. data/lib/krant.rb +57 -0
  37. data/lib/krant/engine.rb +14 -0
  38. data/lib/krant/news.rb +102 -0
  39. data/lib/krant/tasks.rb +26 -0
  40. data/lib/krant/version.rb +3 -0
  41. data/lib/krant/views/header_with_broadcast_messages.rb +20 -0
  42. data/lib/krant/views/news_list.rb +36 -0
  43. metadata +281 -0
@@ -0,0 +1,2 @@
1
+ @import "./active_admin/broadcast_messages";
2
+ @import "./active_admin/news_list";
@@ -0,0 +1,31 @@
1
+ $krant-broadcast-message-bar-color: #f6efce !default;
2
+ $krant-broadcast-message-bar-border-color: #dedede !default;
3
+
4
+ .krant-broadcast-messages {
5
+ &-table-text {
6
+ white-space: nowrap;
7
+
8
+ &-locale,
9
+ &-translation {
10
+ display: inline-block;
11
+ }
12
+
13
+ &-locale {
14
+ font-weight: bold;
15
+ min-width: 2em;
16
+ }
17
+
18
+ &-translation {
19
+ vertical-align: top;
20
+ white-space: normal;
21
+ }
22
+ }
23
+
24
+ &-bar {
25
+ background-color: $krant-broadcast-message-bar-color;
26
+ border-left: solid 1px $krant-broadcast-message-bar-border-color;
27
+ border-right: solid 1px $krant-broadcast-message-bar-border-color;
28
+ padding: 10px $horizontal-page-margin;
29
+ text-align: center;
30
+ }
31
+ }
@@ -0,0 +1,19 @@
1
+ $krant-news-list-item-marker-color: #eee !default;
2
+ $krant-unseen-news-list-item-marker-color: #63a0e8 !default;
3
+ $krant-unseen-news-list-item-marker-width: 2px !default;
4
+ $krant-unseen-news-list-item-padding: 1em !default;
5
+ $krant-unseen-news-list-item-background-color: #eee !default;
6
+
7
+ .krant-news-list {
8
+ margin-left: -$krant-unseen-news-list-item-marker-width;
9
+ }
10
+
11
+ .krant-news-list-item {
12
+ border-left: solid $krant-unseen-news-list-item-marker-width $krant-news-list-item-marker-color;
13
+ margin-left: -$krant-unseen-news-list-item-padding;
14
+ padding: 0 $krant-unseen-news-list-item-padding;
15
+
16
+ &-unseen {
17
+ border-left: solid $krant-unseen-news-list-item-marker-width $krant-unseen-news-list-item-marker-color;
18
+ }
19
+ }
@@ -0,0 +1,10 @@
1
+ module Krant
2
+ # @api private
3
+ class BroadcastMessage < ActiveRecord::Base
4
+ has_many(:translations, class_name: 'BroadcastMessageTranslation')
5
+
6
+ accepts_nested_attributes_for(:translations)
7
+
8
+ scope(:active, -> { where(active: true) })
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module Krant
2
+ # @api private
3
+ class BroadcastMessageTranslation < ActiveRecord::Base
4
+ belongs_to :broadcast_message
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Krant
2
+ # @api private
3
+ class LastSeenState < ActiveRecord::Base
4
+ belongs_to :user, polymorphic: true
5
+ end
6
+ end
@@ -0,0 +1,35 @@
1
+ module Krant
2
+ # @api private
3
+ class NewsItem < ActiveRecord::Base
4
+ attr_accessor :template
5
+ attr_accessor :seen
6
+
7
+ def title
8
+ translated_attribute('title')
9
+ end
10
+
11
+ def text
12
+ translated_attribute('text')
13
+ end
14
+
15
+ def unseen?
16
+ !seen
17
+ end
18
+
19
+ def seen?
20
+ seen
21
+ end
22
+
23
+ private
24
+
25
+ def translated_attribute(name)
26
+ attribute_translations(name).fetch(I18n.locale.to_sym) do
27
+ attribute_translations(name).fetch(I18n.default_locale.to_sym, '')
28
+ end
29
+ end
30
+
31
+ def attribute_translations(name)
32
+ template.fetch(name.to_sym, {})
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+ module Krant
2
+ # @api private
3
+ class TranslatedBroadcastMessage
4
+ attr_reader :text
5
+
6
+ def initialize(text)
7
+ @text = text
8
+ end
9
+
10
+ def self.active
11
+ Query.new.active
12
+ end
13
+
14
+ # @api private
15
+ class Query
16
+ def active
17
+ scope = BroadcastMessage.active
18
+
19
+ scope = with_translation(scope, 'current_locale', I18n.locale)
20
+ scope = with_translation(scope, 'default_locale', I18n.default_locale)
21
+
22
+ scope.map do |broadcast_message|
23
+ TranslatedBroadcastMessage.new(broadcast_message.current_locale_text.presence ||
24
+ broadcast_message.default_locale_text)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def with_translation(scope, name, locale)
31
+ table_alias = "#{name}_translations"
32
+
33
+ scope
34
+ .select("#{table_alias}.text as #{name}_text")
35
+ .joins(sanitize_sql(<<-SQL, locale))
36
+ LEFT JOIN krant_broadcast_message_translations #{table_alias}
37
+ ON #{table_alias}.broadcast_message_id = krant_broadcast_messages.id AND
38
+ #{table_alias}.locale = ?
39
+ SQL
40
+ end
41
+
42
+ def sanitize_sql(sql, interpolations)
43
+ ActiveRecord::Base.send(:sanitize_sql_array, [sql, interpolations])
44
+ end
45
+ end
46
+ end
47
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "krant"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/rails ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/krant/engine', __FILE__)
6
+
7
+ # Set up gems listed in the Gemfile.
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
10
+
11
+ require 'rails/all'
12
+ require 'rails/engine/commands'
data/bin/rspec ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rspec' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("rspec-core", "rspec")
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,23 @@
1
+ de:
2
+ krant:
3
+ admin:
4
+ broadcast_messages:
5
+ text_translation_label: "Text (%{locale_name}):"
6
+ news_menu_item:
7
+ unseen: "Neuigkeiten*"
8
+ no_unseen: "Neuigkeiten"
9
+ activerecord:
10
+ models:
11
+ # Required for ActiveAdmin navigation
12
+ broadcast_message:
13
+ one: "Broadcast Nachricht"
14
+ other: "Broadcast Nachrichten"
15
+ "krant/broadcast_message":
16
+ one: "Broadcast Nachricht"
17
+ other: "Broadcast Nachrichten"
18
+ attributes:
19
+ "krant/broadcast_message":
20
+ text: "Text"
21
+ active: "Aktiv"
22
+ created_at: "Erstellt am"
23
+ updated_at: "Geändert am"
@@ -0,0 +1,23 @@
1
+ en:
2
+ krant:
3
+ admin:
4
+ broadcast_messages:
5
+ text_translation_label: "Text (%{locale_name}):"
6
+ news_menu_item:
7
+ unseen: "What's new*"
8
+ no_unseen: "What's new"
9
+ activerecord:
10
+ models:
11
+ # Required for ActiveAdmin navigation
12
+ broadcast_message:
13
+ one: "Broadcast Message"
14
+ other: "Broadcast Messages"
15
+ "krant/broadcast_message":
16
+ one: "Broadcast Message"
17
+ other: "Broadcast Messages"
18
+ attributes:
19
+ "krant/broadcast_message":
20
+ text: "Text"
21
+ active: "Active"
22
+ created_at: "Created at"
23
+ updated_at: "Updated at"
@@ -0,0 +1,9 @@
1
+ class CreateKrantBroadcastMessages < ActiveRecord::Migration
2
+ def change
3
+ create_table :krant_broadcast_messages do |t|
4
+ t.boolean :active
5
+
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateKrantBroadcastMessageTranslations < ActiveRecord::Migration
2
+ def change
3
+ create_table :krant_broadcast_message_translations do |t|
4
+ t.belongs_to(:broadcast_message,
5
+ index: { name: 'index_krant_broadcast_message_translations_on_message_id' })
6
+ t.string :locale
7
+ t.text :text
8
+
9
+ t.timestamps null: false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ class CreateKrantNewsItems < ActiveRecord::Migration
2
+ def change
3
+ create_table :krant_news_items do |t|
4
+ t.string :scope
5
+ t.string :name
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateKrantLastSeenStates < ActiveRecord::Migration
2
+ def change
3
+ create_table :krant_last_seen_states do |t|
4
+ t.string :scope
5
+ t.belongs_to :user, index: true, polymorphic: true
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.2"
6
+ gem "activeadmin", "1.0.0.pre4"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.2"
6
+ gem "activeadmin", "~> 1.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.2"
6
+ gem "activeadmin", "~> 1.1"
7
+
8
+ gemspec path: "../"
data/krant.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'krant/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'krant'
8
+ spec.version = Krant::VERSION
9
+ spec.authors = ['Tim Fischbach']
10
+ spec.email = ['tfischbach@codevise.de']
11
+
12
+ spec.summary = 'Display app news and broadcast messages in Active Admin.'
13
+ spec.homepage = 'https://github.com/codevise/krant'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.required_ruby_version = '~> 2.1'
22
+
23
+ spec.add_development_dependency 'appraisal', '~> 2.2'
24
+ spec.add_development_dependency 'bundler', '~> 1.14'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec-rails', '~> 3.6'
27
+ spec.add_development_dependency 'combustion', '~> 0.7.0'
28
+ spec.add_development_dependency 'sqlite3', '~> 1.3'
29
+ spec.add_development_dependency 'capybara', '~> 2.15'
30
+ spec.add_development_dependency 'factory_bot_rails', '~> 4.8'
31
+ spec.add_development_dependency 'domino', '~> 0.7.0'
32
+ spec.add_development_dependency 'semmy', '~> 1.0'
33
+ spec.add_development_dependency 'timecop', '~> 0.7.1'
34
+
35
+ spec.add_runtime_dependency 'activeadmin', '~> 1.x'
36
+ spec.add_runtime_dependency 'rails', '~> 4.2'
37
+ spec.add_runtime_dependency 'kramdown', '~> 1.5'
38
+ end
data/lib/krant.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'krant/engine'
2
+ require 'krant/news'
3
+ require 'krant/version'
4
+ require 'krant/views/header_with_broadcast_messages'
5
+ require 'krant/views/news_list'
6
+
7
+ # Global settings
8
+ module Krant
9
+ # Determines for which locales text boxes should be displayed in the
10
+ # broadcast message edit form.
11
+ mattr_accessor :broadcast_message_locales
12
+ self.broadcast_message_locales = [:en, :de]
13
+
14
+ # Unshift to Active Admin load path.
15
+ def self.active_admin_load_path
16
+ Dir[Krant::Engine.root.join('admin')].first
17
+ end
18
+
19
+ # Adds a menu item to open a news page. Displays an indicator if
20
+ # there are unseen news items. Supports all parameters supported by
21
+ # `ActiveAdmin::Menu#add`. Required options:
22
+ #
23
+ # @param menu [ActiveAdmin::Menu] The menu object yielded by
24
+ # `ActiveAdmin::Namespace#build_menu`.
25
+ #
26
+ # @param news [Krant::News] The news collection to take news item
27
+ # from.
28
+ #
29
+ # @param url [Proc|String] Url of the news page.
30
+ def self.add_active_admin_news_menu_item_to(menu, news:, **options)
31
+ menu.add(label: -> { I18n.t('krant.admin.news_menu_item.unseen') },
32
+ id: 'krant_news_menu_item_unseen',
33
+ if: -> { news.unseen_items?(for_user: current_active_admin_user) },
34
+ html_options: { class: 'krant-news-menu-item krant-news-menu-item-unseen' },
35
+ **options)
36
+
37
+ menu.add(label: -> { I18n.t('krant.admin.news_menu_item.no_unseen') },
38
+ id: 'krant_news_menu_item_no_unseen',
39
+ if: -> { !news.unseen_items?(for_user: current_active_admin_user) },
40
+ html_options: { class: 'krant-news-menu-item krant-news-menu-item-no-unseen' },
41
+ **options)
42
+ end
43
+
44
+ # Apply default settings to news page.
45
+ #
46
+ # @param page [ActiveAdmin::PageDSL] The admin page.
47
+ #
48
+ # @param news [Proc] Proc returing the news collection.
49
+ def self.active_admin_news_page(page, news:)
50
+ page.menu(false)
51
+
52
+ page.page_action(:seen, method: [:post]) do
53
+ news.call.seen_by!(current_active_admin_user)
54
+ render text: ''
55
+ end
56
+ end
57
+ end