Merge branch 'develop' into search_member_uid
Conflicts: app/views/users/index.html.erb
This commit is contained in:
@@ -12,7 +12,6 @@
|
||||
# database setup:
|
||||
DATABASE_ADAPTER=postgres
|
||||
DATABASE_USER=postgres
|
||||
DATABASE_PASSWORD=postgres
|
||||
DATABASE_HOST=localhost
|
||||
|
||||
# host part of the url for mail links:
|
||||
|
||||
@@ -23,6 +23,11 @@ gem 'prawn-table', '~> 0.2.2'
|
||||
gem 'elasticsearch-model'
|
||||
gem 'elasticsearch-rails'
|
||||
gem 'skylight'
|
||||
gem 'sidekiq', '5.1.3'
|
||||
gem 'sidekiq-cron', '0.6.3'
|
||||
# TODO: remove this once the following issue has been addressed
|
||||
# https://github.com/ondrejbartas/sidekiq-cron/issues/199
|
||||
gem 'rufus-scheduler', '~> 3.4.2'
|
||||
|
||||
# Assets
|
||||
gem 'jquery-rails', '>= 4.2.0'
|
||||
@@ -54,7 +59,7 @@ end
|
||||
|
||||
group :test do
|
||||
gem "database_cleaner", '1.6.2'
|
||||
gem 'shoulda', ">= 3.5"
|
||||
gem 'shoulda-matchers', '~> 3.1.2'
|
||||
gem 'fabrication'
|
||||
gem 'faker'
|
||||
gem 'capybara', '~> 2.7'
|
||||
|
||||
+23
-8
@@ -112,6 +112,7 @@ GEM
|
||||
coffee-script-source (1.8.0)
|
||||
columnize (0.9.0)
|
||||
concurrent-ruby (1.0.5)
|
||||
connection_pool (2.2.1)
|
||||
crass (1.0.3)
|
||||
dalli (2.7.2)
|
||||
database_cleaner (1.6.2)
|
||||
@@ -143,6 +144,8 @@ GEM
|
||||
multi_json
|
||||
erubi (1.7.1)
|
||||
erubis (2.7.0)
|
||||
et-orbi (1.1.2)
|
||||
tzinfo
|
||||
execjs (2.6.0)
|
||||
fabrication (2.11.3)
|
||||
faker (1.4.3)
|
||||
@@ -239,6 +242,8 @@ GEM
|
||||
pundit (0.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
rack (1.6.9)
|
||||
rack-protection (2.0.1)
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.2.10)
|
||||
@@ -283,6 +288,7 @@ GEM
|
||||
i18n
|
||||
polyamorous (~> 1.3.2)
|
||||
rdiscount (2.1.7.1)
|
||||
redis (4.0.1)
|
||||
responders (2.0.2)
|
||||
railties (>= 4.2.0.alpha, < 5)
|
||||
rest-client (2.0.1)
|
||||
@@ -317,6 +323,8 @@ GEM
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-progressbar (1.9.0)
|
||||
rubyzip (1.2.1)
|
||||
rufus-scheduler (3.4.2)
|
||||
et-orbi (~> 1.0)
|
||||
sass (3.4.21)
|
||||
sass-rails (5.0.7)
|
||||
railties (>= 4.0.0, < 6)
|
||||
@@ -329,12 +337,16 @@ GEM
|
||||
selenium-webdriver (3.11.0)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.2)
|
||||
shoulda (3.5.0)
|
||||
shoulda-context (~> 1.0, >= 1.0.1)
|
||||
shoulda-matchers (>= 1.4.1, < 3.0)
|
||||
shoulda-context (1.2.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
shoulda-matchers (3.1.2)
|
||||
activesupport (>= 4.0.0)
|
||||
sidekiq (5.1.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
rack-protection (>= 1.5.0)
|
||||
redis (>= 3.3.5, < 5)
|
||||
sidekiq-cron (0.6.3)
|
||||
rufus-scheduler (>= 3.3.0)
|
||||
sidekiq (>= 4.2.1)
|
||||
simple_form (3.1.0)
|
||||
actionpack (~> 4.0)
|
||||
activemodel (~> 4.0)
|
||||
@@ -425,9 +437,12 @@ DEPENDENCIES
|
||||
rollbar (= 2.8.3)
|
||||
rspec-rails (~> 3.7.2)
|
||||
rubocop (~> 0.52.1)
|
||||
rufus-scheduler (~> 3.4.2)
|
||||
sass-rails (~> 5.0.7)
|
||||
select2-rails
|
||||
shoulda (>= 3.5)
|
||||
shoulda-matchers (~> 3.1.2)
|
||||
sidekiq (= 5.1.3)
|
||||
sidekiq-cron (= 0.6.3)
|
||||
simple_form (>= 3.0.0)
|
||||
skylight
|
||||
uglifier (= 2.7.2)
|
||||
@@ -439,4 +454,4 @@ RUBY VERSION
|
||||
ruby 2.3.0p0
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.1
|
||||
1.16.2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# TimeOverflow [](https://travis-ci.org/coopdevs/timeoverflow) [](https://codeclimate.com/github/timeoverflow/timeoverflow)
|
||||
# TimeOverflow [](https://oss.skylight.io/app/applications/grDTNuzZRnyu) [](https://travis-ci.org/coopdevs/timeoverflow) [](https://codeclimate.com/github/timeoverflow/timeoverflow)
|
||||
#### www.timeoverflow.org
|
||||
|
||||
:globe_with_meridians: Read this [in English](docs/README.en.md)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 891 KiB After Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 592 KiB |
@@ -0,0 +1,60 @@
|
||||
/*!
|
||||
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*
|
||||
* This file lists all the available Bootstrap modules, uncomment
|
||||
* the modules you want to import
|
||||
*/
|
||||
|
||||
// Core variables and mixins
|
||||
@import "bootstrap-overrides";
|
||||
@import "bootstrap/variables";
|
||||
@import "bootstrap/mixins";
|
||||
|
||||
// Reset and dependencies
|
||||
@import "bootstrap/normalize";
|
||||
@import "bootstrap/print";
|
||||
@import "bootstrap/glyphicons";
|
||||
|
||||
// Core CSS
|
||||
@import "bootstrap/scaffolding";
|
||||
@import "bootstrap/type";
|
||||
@import "bootstrap/code";
|
||||
@import "bootstrap/grid";
|
||||
@import "bootstrap/tables";
|
||||
@import "bootstrap/forms";
|
||||
@import "bootstrap/buttons";
|
||||
|
||||
// Components
|
||||
@import "bootstrap/component-animations";
|
||||
@import "bootstrap/dropdowns";
|
||||
@import "bootstrap/button-groups";
|
||||
@import "bootstrap/input-groups";
|
||||
@import "bootstrap/navs";
|
||||
@import "bootstrap/navbar";
|
||||
// @import "bootstrap/breadcrumbs";
|
||||
@import "bootstrap/pagination";
|
||||
@import "bootstrap/pager";
|
||||
@import "bootstrap/labels";
|
||||
@import "bootstrap/badges";
|
||||
// @import "bootstrap/jumbotron";
|
||||
// @import "bootstrap/thumbnails";
|
||||
@import "bootstrap/alerts";
|
||||
// @import "bootstrap/progress-bars";
|
||||
@import "bootstrap/media";
|
||||
@import "bootstrap/list-group";
|
||||
@import "bootstrap/panels";
|
||||
@import "bootstrap/responsive-embed";
|
||||
// @import "bootstrap/wells";
|
||||
@import "bootstrap/close";
|
||||
|
||||
// Components w/ JavaScript
|
||||
@import "bootstrap/modals";
|
||||
@import "bootstrap/tooltip";
|
||||
// @import "bootstrap/popovers";
|
||||
// @import "bootstrap/carousel";
|
||||
|
||||
// Utility classes
|
||||
@import "bootstrap/utilities";
|
||||
@import "bootstrap/responsive-utilities";
|
||||
@@ -0,0 +1,13 @@
|
||||
$brand-primary: $palette-turkey;
|
||||
|
||||
$navbar-inverse-brand-hover-color: $palette-light-blue;
|
||||
$navbar-inverse-brand-color: $white;
|
||||
|
||||
$navbar-inverse-link-color: $white;
|
||||
$navbar-inverse-link-active-color: $palette-light-blue;
|
||||
$navbar-inverse-link-active-bg: $palette-turkey;
|
||||
$navbar-inverse-link-hover-color: $palette-light-blue;
|
||||
$navbar-inverse-toggle-border-color: $white;
|
||||
$navbar-inverse-toggle-hover-bg: $palette-dark-turkey;
|
||||
|
||||
$navbar-inverse-bg: $palette-turkey;
|
||||
@@ -0,0 +1,86 @@
|
||||
.language-selector {
|
||||
& {
|
||||
display: inline-block;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
a.btn-default.dropdown-toggle {
|
||||
& {
|
||||
background-color: transparent;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.open > a.btn-default.dropdown-toggle {
|
||||
& {
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
border-color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 8px 0;
|
||||
line-height: 40px;
|
||||
width: 100%;
|
||||
background: rgba($palette-dark-turkey ,0.8);
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
margin: 0 1rem;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-left-col {
|
||||
text-align: left;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-center-col {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-right-col {
|
||||
text-align: right;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-page, .login-page, .pages, .unlocks-page, .confirmations-page, .passwords-page {
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
.to-categories-dropdown {
|
||||
@media(max-width: $screen-sm-min) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// New palette
|
||||
$palette-turkey: #2797af;
|
||||
$palette-dark-turkey: #165e6d;
|
||||
$palette-light-blue: #d9edf7;
|
||||
$palette-grey: #aaa;
|
||||
$palette-black: #333;
|
||||
|
||||
// Old colors
|
||||
$bg-color: #f5f8fa;
|
||||
$white: #ffffff;
|
||||
$border: #e1e8ed;
|
||||
$menu-disabled: #ddd;
|
||||
$black: #000;
|
||||
$form-input-glyph: #555;
|
||||
$form-input-bg-color: #f5f5f5;
|
||||
$form-input-button: #2a292a;
|
||||
$form-input-button-hover: #3a393a;
|
||||
$form-a-color: gray;
|
||||
$form-a-hover-color: $palette-black;
|
||||
$form-login-gray-text: #9b9b9b;
|
||||
$btn-landing: rgba(255, 255, 255, 0.7);
|
||||
$btn-landing-hover: rgba(255, 255, 255, 0.9);
|
||||
$pages-title: #4a4a4a;
|
||||
$pages-text: #4a4a4a;
|
||||
$pages-anchor: #4a4a4a;
|
||||
$pages-anchor-hover: #8a8a8a;
|
||||
$features-background: #f5f5f5;
|
||||
$features-separator: #d8d8d8;
|
||||
|
||||
@@ -2,64 +2,45 @@
|
||||
*= require_self
|
||||
*/
|
||||
|
||||
@import "variables";
|
||||
@import "bootstrap-sprockets";
|
||||
@import "bootstrap";
|
||||
|
||||
$bg-color: #f5f8fa;
|
||||
$navs-bg-color: #1e1e1e;
|
||||
$white: #ffffff;
|
||||
$border: #e1e8ed;
|
||||
$navs-hover-color: #aaa;
|
||||
$menu-drop: #333;
|
||||
$menu-drop-hover: #333;
|
||||
$menu-disabled: #ddd;
|
||||
$black: #000;
|
||||
$form-input-glyph: #555;
|
||||
$form-input-bg-color: #f5f5f5;
|
||||
$form-input-button: #2a292a;
|
||||
$form-input-button-hover: #3a393a;
|
||||
$form-a-color: gray;
|
||||
$form-a-hover-color: #333;
|
||||
$form-login-gray-text: #9b9b9b;
|
||||
$btn-landing: rgba(255, 255, 255, 0.7);
|
||||
$btn-landing-hover: rgba(255, 255, 255, 0.9);
|
||||
$pages-title: #4a4a4a;
|
||||
$pages-text: #4a4a4a;
|
||||
$pages-anchor: #4a4a4a;
|
||||
$pages-anchor-hover: #8a8a8a;
|
||||
$features-background: #f5f5f5;
|
||||
$features-separator: #d8d8d8;
|
||||
@import "bootstrap-custom";
|
||||
@import "to-categories-dropdown";
|
||||
@import "footer";
|
||||
|
||||
html {
|
||||
font-size:62.5%;
|
||||
font-size: 62.5%;
|
||||
}
|
||||
|
||||
.content
|
||||
{
|
||||
min-height:500px;
|
||||
margin-bottom: 40px;
|
||||
.content {
|
||||
min-height: 500px;
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
.language-selector{
|
||||
margin: 1.2rem 3rem 1.2rem 1rem;
|
||||
}
|
||||
.actions-menu {
|
||||
margin-bottom: 16px;
|
||||
padding: 0 15px;
|
||||
|
||||
.language-selector a span {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.actions-menu > .dropdown > .language b {
|
||||
display: inline-block;
|
||||
margin-left: 0.7rem;
|
||||
@media(max-width: $screen-sm-min) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.actions-menu > li > a {
|
||||
color: #101010;
|
||||
padding: 10px 16px;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.actions-menu > li{
|
||||
margin-right:5px;
|
||||
.actions-menu > li {
|
||||
margin-right: 6px;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
#login-box {
|
||||
@@ -90,14 +71,6 @@ html {
|
||||
transition: background-color 100000s ease-in-out 0s;
|
||||
}
|
||||
|
||||
span.input-group-addon {
|
||||
padding: 2rem 2rem 2rem 3rem;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
span.show-password {
|
||||
border-radius: 0 0.3rem 0.3rem 0;
|
||||
cursor: pointer;
|
||||
@@ -124,10 +97,6 @@ html {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
padding: 0 3rem 0 3rem;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
padding: 2rem 3rem;
|
||||
|
||||
@@ -160,7 +129,6 @@ html {
|
||||
color: $form-input-glyph;
|
||||
font-size: 2.24rem;
|
||||
letter-spacing: -0.0040rem;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
@@ -198,7 +166,7 @@ html {
|
||||
background-color: $white;
|
||||
border: 1px solid $border;
|
||||
border-radius: 5px;
|
||||
margin: 10px;
|
||||
margin: 14px 0;
|
||||
padding: 5px 20px;
|
||||
|
||||
h4 {
|
||||
@@ -216,6 +184,12 @@ html {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&__datetime {
|
||||
color: $palette-grey;
|
||||
padding: 4px 0 0;
|
||||
font-size: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.break-word {
|
||||
@@ -231,36 +205,6 @@ html {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
line-height: 40px;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
vertical-align: middle;
|
||||
width: 100%;
|
||||
|
||||
p {
|
||||
font-size: 1.6rem;
|
||||
letter-spacing: 0.013rem;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $pages-anchor;
|
||||
font-weight: 500;
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $pages-anchor-hover;
|
||||
}
|
||||
}
|
||||
|
||||
.row.exports {
|
||||
padding: 10px;
|
||||
@@ -285,7 +229,6 @@ table.users {
|
||||
background-color: $bg-color;
|
||||
font-family: 'Work Sans', "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: medium;
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
|
||||
form {
|
||||
@@ -409,8 +352,13 @@ label[required]::after{
|
||||
}
|
||||
|
||||
.navbar-form {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
|
||||
@media(max-width: $screen-sm-min) {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
form .checkbox input[type="checkbox"] {
|
||||
@@ -429,7 +377,11 @@ form .checkbox input[type="checkbox"] {
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.navbar-block{
|
||||
.navbar .container-fluid {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navbar-block {
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
@@ -442,104 +394,19 @@ form .checkbox input[type="checkbox"] {
|
||||
}
|
||||
|
||||
.navbar-static-top {
|
||||
background-color: $navs-bg-color;
|
||||
background-color: rgba($palette-turkey, 0.9);
|
||||
}
|
||||
|
||||
.navbar-inverse {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand a:hover, .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus {
|
||||
color: $navs-hover-color;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 2.4rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.019rem;
|
||||
}
|
||||
|
||||
.language-selector{
|
||||
margin: 0.5rem 2rem 0 2rem;
|
||||
width: 13.5rem;
|
||||
}
|
||||
|
||||
.dropdown{
|
||||
&.dropdown-language-selector{
|
||||
.dropdown-toggle{
|
||||
background: none;
|
||||
border: 0.2rem solid $white;
|
||||
border-radius: 0.3rem;
|
||||
color: $white;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 500;
|
||||
min-width: 13.5rem;
|
||||
text-align: left;
|
||||
|
||||
.caret{
|
||||
display: block;
|
||||
float: right;
|
||||
margin-top: 1.1rem;
|
||||
}
|
||||
&:focus,
|
||||
&:active{
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
&.open>.btn-default.dropdown-toggle{
|
||||
background: none;
|
||||
border-color: $white;
|
||||
border-bottom: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
color: $white;
|
||||
|
||||
.caret{
|
||||
-ms-transform: rotate(180deg);
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
.dropdown-menu{
|
||||
background: $navs-bg-color;
|
||||
border: 0.2rem solid $white;
|
||||
border-top: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
box-shadow: none;
|
||||
margin-top: 0;
|
||||
min-width: 13.5rem;
|
||||
li{
|
||||
a{
|
||||
color: $white;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 500;
|
||||
padding: 0.6rem 1.2rem;
|
||||
&:hover{
|
||||
background: $menu-drop-hover;
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:focus,
|
||||
&:active{
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.landing-page, .login-page, .pages, .unlocks-page, .confirmations-page, .passwords-page {
|
||||
background: image-url('home_back.jpg') no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
@@ -547,18 +414,15 @@ form .checkbox input[type="checkbox"] {
|
||||
.back-overlay {
|
||||
display: block;
|
||||
filter: alpha(opacity = 60); /* For IE8 and earlier */
|
||||
opacity: 0.6;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.vertical-align {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 47%;
|
||||
top: 48%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 75%;
|
||||
}
|
||||
.container-fluid {
|
||||
padding-bottom: 0.8rem;
|
||||
padding-top: 0.8rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container-inner {
|
||||
@@ -578,7 +442,7 @@ form .checkbox input[type="checkbox"] {
|
||||
|
||||
.landing-page {
|
||||
background: image-url('home_back.jpg') no-repeat center center fixed;
|
||||
background-color: $navs-bg-color;
|
||||
background-color: $palette-turkey;
|
||||
background-size: cover;
|
||||
text-align: center;
|
||||
|
||||
@@ -595,6 +459,7 @@ form .checkbox input[type="checkbox"] {
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.073rem;
|
||||
margin: 0;
|
||||
text-shadow: 1px 1px $palette-black;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@@ -603,6 +468,7 @@ form .checkbox input[type="checkbox"] {
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.107rem;
|
||||
margin-top: 1rem;
|
||||
text-shadow: 1px 1px $palette-black;
|
||||
}
|
||||
|
||||
.btn {
|
||||
@@ -625,18 +491,6 @@ form .checkbox input[type="checkbox"] {
|
||||
}
|
||||
|
||||
.login-page {
|
||||
h1 {
|
||||
font-size: 3.84rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.031rem;
|
||||
margin-bottom: 2rem;
|
||||
margin-top: 3rem;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-size: 3rem;
|
||||
}
|
||||
@@ -682,10 +536,6 @@ form .checkbox input[type="checkbox"] {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#login-box .panel-body {
|
||||
padding: 3rem 3rem 2rem 3rem;
|
||||
}
|
||||
|
||||
.panel-body h2 {
|
||||
font-size: 1.9rem;
|
||||
font-weight: 500;
|
||||
@@ -786,7 +636,7 @@ form .checkbox input[type="checkbox"] {
|
||||
}
|
||||
|
||||
.banner {
|
||||
background: image-url('home_back_overlay.jpg') no-repeat center center;
|
||||
background: image-url('home_back.jpg') no-repeat center center;
|
||||
background-size: cover;
|
||||
margin: 8rem 0 3rem 0;
|
||||
padding: 8rem 1rem;
|
||||
@@ -831,79 +681,14 @@ form .checkbox input[type="checkbox"] {
|
||||
}
|
||||
}
|
||||
|
||||
.footer-left-col, .footer-left-col p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.footer-center, .footer-center-col p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-right-col, .footer-right-col p {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media(max-width:767px){
|
||||
html{
|
||||
font-size:55.5%;
|
||||
}
|
||||
|
||||
.footer-left-col, .footer-left-col p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-center-col, .footer-center-col p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-right-col, .footer-right-col p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 4rem;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.landing-page, .login-page, .pages, .unlocks-page, .confirmations-page, .passwords-page {
|
||||
.language-selector{
|
||||
margin: 0 auto;
|
||||
width: 13.5rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
bottom: 1rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.footer a{
|
||||
margin-left: 0rem;
|
||||
}
|
||||
|
||||
.footer-right-col a{
|
||||
margin: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.landing-page, .unlocks-page, .confirmations-page, .passwords-page {
|
||||
.footer {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.login-page {
|
||||
.vertical-align{
|
||||
height: auto;
|
||||
position: static;
|
||||
top: 0;
|
||||
transform: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.errors {
|
||||
@@ -916,4 +701,4 @@ form .checkbox input[type="checkbox"] {
|
||||
padding: 1em;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
class OrganizationsController < ApplicationController
|
||||
before_filter :load_resource
|
||||
|
||||
def load_resource
|
||||
if params[:id]
|
||||
@organization = Organization.find(params[:id])
|
||||
else
|
||||
@organizations = Organization.all
|
||||
end
|
||||
end
|
||||
before_filter :load_resource, only: [:show, :edit, :update, :destroy]
|
||||
|
||||
def new
|
||||
@organization = Organization.new
|
||||
end
|
||||
|
||||
def index
|
||||
@organizations = @organizations.matching(params[:q]) if params[:q].present?
|
||||
@organizations = Organization.all
|
||||
end
|
||||
|
||||
def show
|
||||
@@ -27,7 +19,8 @@ class OrganizationsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
@organization = @organizations.build organization_params
|
||||
@organization = Organization.new(organization_params)
|
||||
|
||||
if @organization.save
|
||||
redirect_to @organization, status: :created
|
||||
else
|
||||
@@ -57,6 +50,10 @@ class OrganizationsController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def load_resource
|
||||
@organization = Organization.find(params[:id])
|
||||
end
|
||||
|
||||
def organization_params
|
||||
params[:organization].permit(*%w[name theme email phone web
|
||||
public_opening_times description address
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
class CreatePushNotificationsJob < ActiveJob::Base
|
||||
queue_as :default
|
||||
|
||||
def perform(event_id:)
|
||||
event = ::Event.find_by_id(event_id)
|
||||
|
||||
raise 'A valid Event must be provided' unless event
|
||||
|
||||
::PushNotifications::Creator.new(event: event).create!
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
class Event < ActiveRecord::Base
|
||||
enum action: { created: 0, updated: 1 }
|
||||
|
||||
belongs_to :post
|
||||
belongs_to :member
|
||||
belongs_to :transfer
|
||||
|
||||
validates :action, presence: true
|
||||
validate :resource_presence
|
||||
|
||||
private
|
||||
|
||||
# Validates that only one resource id is set
|
||||
#
|
||||
def resource_presence
|
||||
return if post_id.present? ^ member_id.present? ^ transfer_id.present?
|
||||
|
||||
errors.add(:base, 'Specify only one resource id: `post_id`, `member_id` or `transfer_id`')
|
||||
end
|
||||
end
|
||||
@@ -2,11 +2,7 @@ class Organization < ActiveRecord::Base
|
||||
has_many :members, dependent: :destroy
|
||||
has_many :users, -> { order "members.created_at DESC" }, through: :members
|
||||
has_many :all_accounts, class_name: "Account", inverse_of: :organization
|
||||
has_many :all_movements, class_name: "Movement", through: :all_accounts, source: :movements do
|
||||
def with_transfer
|
||||
joins(transfer: :movements)
|
||||
end
|
||||
end
|
||||
has_many :all_movements, class_name: "Movement", through: :all_accounts, source: :movements
|
||||
has_many :all_transfers, class_name: "Transfer", through: :all_movements, source: :transfer
|
||||
has_one :account, as: :accountable
|
||||
has_many :member_accounts, through: :members, source: :account
|
||||
@@ -15,11 +11,7 @@ class Organization < ActiveRecord::Base
|
||||
has_many :inquiries
|
||||
has_many :documents, as: :documentable
|
||||
|
||||
scope :matching, ->(str) {
|
||||
where(Organization.arel_table[:name].matches("%#{str}%"))
|
||||
}
|
||||
|
||||
validates :name, uniqueness: true
|
||||
validates :name, presence: true, uniqueness: true
|
||||
|
||||
before_validation :ensure_url
|
||||
after_create :create_account
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class PushNotification < ActiveRecord::Base
|
||||
belongs_to :event, foreign_key: 'event_id'
|
||||
belongs_to :device_token, foreign_key: 'device_token_id'
|
||||
|
||||
validates :event, :device_token, presence: true
|
||||
end
|
||||
@@ -1,11 +0,0 @@
|
||||
module PushNotifications
|
||||
class PostNotification
|
||||
def title
|
||||
"Notification title"
|
||||
end
|
||||
|
||||
def body
|
||||
"Notification body"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,7 +7,33 @@ module Persister
|
||||
end
|
||||
|
||||
def save
|
||||
member.save
|
||||
::ActiveRecord::Base.transaction do
|
||||
member.save!
|
||||
create_save_event!
|
||||
member
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => _exception
|
||||
false
|
||||
end
|
||||
|
||||
def update_attributes(params)
|
||||
::ActiveRecord::Base.transaction do
|
||||
member.update_attributes!(params)
|
||||
create_update_event!
|
||||
member
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => _exception
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_save_event!
|
||||
::Event.create! action: :created, member: member
|
||||
end
|
||||
|
||||
def create_update_event!
|
||||
::Event.create! action: :updated, member: member
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,11 +7,41 @@ module Persister
|
||||
end
|
||||
|
||||
def save
|
||||
post.save
|
||||
::ActiveRecord::Base.transaction do
|
||||
post.save!
|
||||
create_save_event!
|
||||
enqueue_push_notification_job!
|
||||
post
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => _exception
|
||||
false
|
||||
end
|
||||
|
||||
def update_attributes(params)
|
||||
post.update_attributes(params)
|
||||
::ActiveRecord::Base.transaction do
|
||||
post.update_attributes!(params)
|
||||
create_update_event!
|
||||
enqueue_push_notification_job!
|
||||
post
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => _exception
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :event
|
||||
|
||||
def create_save_event!
|
||||
@event = ::Event.create! action: :created, post: post
|
||||
end
|
||||
|
||||
def create_update_event!
|
||||
@event = ::Event.create! action: :updated, post: post
|
||||
end
|
||||
|
||||
def enqueue_push_notification_job!
|
||||
CreatePushNotificationsJob.perform_later(event_id: event.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,7 +7,33 @@ module Persister
|
||||
end
|
||||
|
||||
def save
|
||||
transfer.save
|
||||
::ActiveRecord::Base.transaction do
|
||||
transfer.save!
|
||||
create_save_event!
|
||||
transfer
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => _exception
|
||||
false
|
||||
end
|
||||
|
||||
def update_attributes(params)
|
||||
::ActiveRecord::Base.transaction do
|
||||
transfer.update_attributes!(params)
|
||||
create_update_event!
|
||||
transfer
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => _exception
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_save_event!
|
||||
::Event.create! action: :created, transfer: transfer
|
||||
end
|
||||
|
||||
def create_update_event!
|
||||
::Event.create! action: :updated, transfer: transfer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
module PushNotifications
|
||||
class Creator
|
||||
# Given an Event it will create as many PushNotification resources
|
||||
# necessary as the resource associated to the Event will require.
|
||||
#
|
||||
# @param [Hash] event: <Event>
|
||||
def initialize(event:)
|
||||
@event = event
|
||||
end
|
||||
|
||||
def create!
|
||||
event_notifier = EventNotifierFactory.new(event: event).build
|
||||
event_notifier.device_tokens.each do |device_token|
|
||||
PushNotification.create!(event: event, device_token: device_token)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :event
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
module PushNotifications
|
||||
module EventNotifier
|
||||
class Post
|
||||
def initialize(event:)
|
||||
@event = event
|
||||
@post = event.post
|
||||
end
|
||||
|
||||
# Conditions for Post:
|
||||
#
|
||||
# We need to notify all the users that:
|
||||
# - are members of the Post's organization
|
||||
# - have a DeviceToken associated
|
||||
#
|
||||
# @return [<DeviceToken>]
|
||||
def device_tokens
|
||||
organization = post.organization
|
||||
DeviceToken.where(user_id: organization.user_ids)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :event, :post
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
module PushNotifications
|
||||
class EventNotifierFactory
|
||||
def initialize(event:)
|
||||
@event = event
|
||||
end
|
||||
|
||||
def build
|
||||
return EventNotifier::Post.new(event: event) if event.post_id
|
||||
|
||||
raise 'The resource associated to the Event is not supported'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :event
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="footer container-fluid">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 footer-left-col">
|
||||
<a href="http://community.coopdevs.org/" target="_blank"><%= t('layouts.application.help') %></a>
|
||||
<%= link_to t('application.terms_conditions'), tnc_path, data: { target: '#modal', toggle: 'modal' } %>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 footer-center-col">
|
||||
<%= render 'application/menus/language_switcher' %>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 footer-right-col">
|
||||
<a href="https://twitter.com/timeoverflow" target="_blank">Twitter</a>
|
||||
<a href="https://github.com/coopdevs/timeoverflow" target="_blank">Github</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -30,9 +30,6 @@
|
||||
<%= link_to t("layouts.application.about"), page_path("about") %>
|
||||
</li>
|
||||
<% end %>
|
||||
<li class="divider" role="presentation"></li>
|
||||
|
||||
<%= render 'application/menus/language_switcher' %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,24 +40,22 @@
|
||||
|
||||
<% if current_user && current_organization %>
|
||||
<nav role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<ul class="nav nav-pills actions-menu">
|
||||
<%= render 'application/menus/user_list_link' %>
|
||||
<%= render 'application/menus/offers_dashboard_link' %>
|
||||
<%= render 'application/menus/inquiries_list_link' %>
|
||||
<%= render 'application/menus/offers_by_tag_link' %>
|
||||
<% if current_user.manages? current_organization %>
|
||||
<%= render 'application/menus/organization_reports_menu' %>
|
||||
<%= render 'application/menus/organization_statistics_menu' %>
|
||||
<%= render 'application/menus/organization_listings_menu' %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<ul class="nav nav-pills actions-menu">
|
||||
<%= render 'application/menus/user_list_link' %>
|
||||
<%= render 'application/menus/offers_dashboard_link' %>
|
||||
<%= render 'application/menus/inquiries_list_link' %>
|
||||
<% if current_user.manages? current_organization %>
|
||||
<%= render 'application/menus/offers_by_tag_link' %>
|
||||
<%= render 'application/menus/organization_reports_menu' %>
|
||||
<%= render 'application/menus/organization_statistics_menu' %>
|
||||
<%= render 'application/menus/organization_listings_menu' %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
<li>
|
||||
<div class="language-selector">
|
||||
<div class="dropdown dropdown-language-selector">
|
||||
<a class="btn btn-default dropdown-toggle language" type="button" id="dropdownLanguage" data-toggle="dropdown">
|
||||
<span><%= t("locales.#{locale}") %></span>
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1" >
|
||||
<% I18n.available_locales.each do |locale| %>
|
||||
<% if I18n.locale != locale %>
|
||||
<li>
|
||||
<%= link_to t("locales.#{locale}"), switch_lang_path(locale: locale) %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div class="dropup language-selector">
|
||||
<a class="btn btn-default dropdown-toggle language" type="button" id="dropdownLanguage" data-toggle="dropdown">
|
||||
<span><%= t("locales.#{locale}") %></span>
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1" >
|
||||
<% I18n.available_locales.each do |locale| %>
|
||||
<% if I18n.locale != locale %>
|
||||
<li>
|
||||
<%= link_to t("locales.#{locale}", locale: locale), switch_lang_path(locale: locale) %>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<li class="<%= "active" if current_page?(users_path) %>">
|
||||
<%= link_to users_path do %>
|
||||
<%= glyph :user %>
|
||||
<%= User.model_name.human(count: :many) %>
|
||||
<%= t("users.index.members") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
<div class="vertical-align">
|
||||
<div class="col-xs-12 col-sm-8 col-md-6 col-lg-6 col-sm-offset-2 col-md-offset-3 col-lg-offset-3">
|
||||
<div class="panel" id="login-box">
|
||||
<div class="panel-heading">
|
||||
<h1>
|
||||
TimeOverflow
|
||||
</h1>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<%= render 'layouts/messages' %>
|
||||
<%= show_error_messages!(resource) %>
|
||||
|
||||
@@ -1,57 +1,77 @@
|
||||
<% @category = Category.where(id: params[:cat]).first %>
|
||||
<h1>
|
||||
<%= Inquiry.model_name.human(count: :many) %>
|
||||
<%= render "shared/show_filter_hint" %>
|
||||
</h1>
|
||||
|
||||
<div class="navbar">
|
||||
<form action="<%= inquiries_path %>"
|
||||
class="navbar-form navbar-left"
|
||||
method="get"
|
||||
role="search">
|
||||
<div class="form-group">
|
||||
<input class="form-control"
|
||||
name="q"
|
||||
placeholder="<%= t("global.search") %>"
|
||||
type="text"
|
||||
value="<%= params[:q] %>">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>
|
||||
<%= Inquiry.model_name.human(count: :many) %>
|
||||
<%= render "shared/show_filter_hint" %>
|
||||
</h1>
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t("global.search") %>
|
||||
</button>
|
||||
</form>
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
|
||||
<%= @category ? @category.name : Category.model_name.human %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<%= link_to "× #{t("global.all")}", inquiries_path %>
|
||||
</li>
|
||||
<% Category.all.sort_by { |a| a.name.downcase }.each do |c| %>
|
||||
<% next if c == @category %>
|
||||
<li>
|
||||
<%= link_to c.name, inquiries_path(cat: c.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<% if current_user && current_organization && !params[:org] %>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<li>
|
||||
<%= link_to new_inquiry_path do %>
|
||||
<%= glyph :plus %>
|
||||
<%= t "helpers.submit.create", model: Inquiry.model_name.human %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inquiries">
|
||||
<%= render "shared/posts", posts: @inquiries %>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<form action="<%= inquiries_path %>"
|
||||
class="navbar-form navbar-left"
|
||||
method="get"
|
||||
role="search">
|
||||
<div class="form-group">
|
||||
<input class="form-control"
|
||||
name="q"
|
||||
placeholder="<%= t("global.search") %>"
|
||||
type="text"
|
||||
value="<%= params[:q] %>">
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t("global.search") %>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<ul class="to-categories-dropdown nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
|
||||
<%= @category ? @category.name : Category.model_name.human %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<%= link_to "× #{t("global.all")}", inquiries_path %>
|
||||
</li>
|
||||
<% Category.all.sort_by { |a| a.name.downcase }.each do |c| %>
|
||||
<% next if c == @category %>
|
||||
<li>
|
||||
<%= link_to c.name, inquiries_path(cat: c.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<% if current_user && current_organization && !params[:org] %>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<li>
|
||||
<%= link_to new_inquiry_path do %>
|
||||
<%= glyph :plus %>
|
||||
<%= t "helpers.submit.create", model: Inquiry.model_name.human %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid inquiries">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<%= render "shared/posts", posts: @inquiries %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= paginate @inquiries %>
|
||||
|
||||
@@ -34,30 +34,9 @@
|
||||
<div class="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer container-fluid">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 footer-left-col">
|
||||
<p>
|
||||
<a href="http://community.coopdevs.org/" target="_blank"><%= t('layouts.application.help') %></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 footer-center-col">
|
||||
<p>
|
||||
<%= link_to t('application.terms_conditions'),
|
||||
tnc_path,
|
||||
data: { target: '#modal', toggle: 'modal' } %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4 footer-right-col">
|
||||
<p>
|
||||
<a href="https://twitter.com/timeoverflow" target="_blank">Twitter</a>
|
||||
<a href="https://github.com/coopdevs/timeoverflow" target="_blank">Github</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render 'application/footer' %>
|
||||
|
||||
<div class="back-overlay"></div>
|
||||
<!-- Piwik -->
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -1,59 +1,78 @@
|
||||
<h1>
|
||||
<%= Offer.model_name.human(count: :many) %>
|
||||
<%= render "shared/show_filter_hint" %>
|
||||
</h1>
|
||||
<div class="navbar">
|
||||
<form action="<%= offers_path %>"
|
||||
class="navbar-form navbar-left"
|
||||
method="get"
|
||||
role="search">
|
||||
<div class="form-group">
|
||||
<input class="form-control"
|
||||
name="q"
|
||||
placeholder="<%= t "global.search" %>"
|
||||
type="text"
|
||||
value="<%= params[:q] %>">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>
|
||||
<%= Offer.model_name.human(count: :many) %>
|
||||
<%= render "shared/show_filter_hint" %>
|
||||
</h1>
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t("global.search") %>
|
||||
</button>
|
||||
</form>
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
|
||||
<%= @category ? @category.name : Category.model_name.human %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<%= link_to "× #{t "global.all"}", offers_path %>
|
||||
</li>
|
||||
<% Category.all.sort_by { |a| a.name.downcase }.each do |c| %>
|
||||
<% next if c == @category %>
|
||||
<li>
|
||||
<%= link_to c.name, offers_path(cat: c.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<li>
|
||||
<%= link_to new_offer_path do %>
|
||||
<%= glyph :plus %>
|
||||
<%= t "helpers.submit.create", model: Offer.model_name.human %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% @offers.each do |cat, offs| %>
|
||||
<div class="offers">
|
||||
<h3>
|
||||
<%= cat.name.capitalize %>
|
||||
</h3>
|
||||
<%= render 'shared/posts', posts: offs %>
|
||||
</div>
|
||||
<%= link_to offers_path(cat: cat.id), class: "more btn btn-primary" do %>
|
||||
<%= t('global.more') %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<form action="<%= offers_path %>"
|
||||
class="navbar-form navbar-left"
|
||||
method="get"
|
||||
role="search">
|
||||
<div class="form-group">
|
||||
<input class="form-control"
|
||||
name="q"
|
||||
placeholder="<%= t "global.search" %>"
|
||||
type="text"
|
||||
value="<%= params[:q] %>">
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t("global.search") %>
|
||||
</button>
|
||||
</form>
|
||||
<ul class="to-categories-dropdown nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
|
||||
<%= @category ? @category.name : Category.model_name.human %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<%= link_to "× #{t "global.all"}", offers_path %>
|
||||
</li>
|
||||
<% Category.all.sort_by { |a| a.name.downcase }.each do |c| %>
|
||||
<% next if c == @category %>
|
||||
<li>
|
||||
<%= link_to c.name, offers_path(cat: c.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<li>
|
||||
<%= link_to new_offer_path do %>
|
||||
<%= glyph :plus %>
|
||||
<%= t "helpers.submit.create", model: Offer.model_name.human %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<% @offers.each do |cat, offs| %>
|
||||
<div class="offers">
|
||||
<h3><%= cat.name.capitalize %></h3>
|
||||
<%= render 'shared/posts', posts: offs %>
|
||||
</div>
|
||||
<%= link_to offers_path(cat: cat.id), class: "more btn btn-primary" do %>
|
||||
<%= t('global.more') %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,55 +1,76 @@
|
||||
<h1>
|
||||
<% @category = Category.where(id: params[:cat]).first %>
|
||||
<%= Offer.model_name.human(count: :many) %>
|
||||
<%= render "shared/show_filter_hint" %>
|
||||
</h1>
|
||||
<div class="navbar">
|
||||
<form action="<%= offers_path %>"
|
||||
class="navbar-form navbar-left"
|
||||
method="get"
|
||||
role="search">
|
||||
<div class="form-group">
|
||||
<input class="form-control"
|
||||
name="q"
|
||||
placeholder="<%= t 'global.search' %>"
|
||||
type="text"
|
||||
value="<%= params[:q] %>">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>
|
||||
<% @category = Category.where(id: params[:cat]).first %>
|
||||
<%= Offer.model_name.human(count: :many) %>
|
||||
<%= render "shared/show_filter_hint" %>
|
||||
</h1>
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t 'global.search' %>
|
||||
</button>
|
||||
</form>
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
|
||||
<%= @category ? @category.name : Category.model_name.human %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<%= link_to "× #{t 'global.all'}", dashboard_offers_path %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<form action="<%= offers_path %>"
|
||||
class="navbar-form navbar-left"
|
||||
method="get"
|
||||
role="search">
|
||||
<div class="form-group">
|
||||
<input class="form-control"
|
||||
name="q"
|
||||
placeholder="<%= t 'global.search' %>"
|
||||
type="text"
|
||||
value="<%= params[:q] %>">
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t 'global.search' %>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<ul class="to-categories-dropdown nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
|
||||
<%= @category ? @category.name : Category.model_name.human %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<%= link_to "× #{t 'global.all'}", dashboard_offers_path %>
|
||||
</li>
|
||||
<% Category.all.sort_by { |a| a.name.downcase }.each do |c| %>
|
||||
<% next if c == @category %>
|
||||
<li>
|
||||
<%= link_to c.name, offers_path(cat: c.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
<% Category.all.sort_by { |a| a.name.downcase }.each do |c| %>
|
||||
<% next if c == @category %>
|
||||
<li>
|
||||
<%= link_to c.name, offers_path(cat: c.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<% if current_user && current_organization && !params[:org] %>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<li>
|
||||
<%= link_to new_offer_path do %>
|
||||
<%= glyph :plus %>
|
||||
<%= t "helpers.submit.create", model: Offer.model_name.human %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<% if current_user && current_organization && !params[:org] %>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<li>
|
||||
<%= link_to new_offer_path do %>
|
||||
<%= glyph :plus %>
|
||||
<%= t "helpers.submit.create", model: Offer.model_name.human %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="offers">
|
||||
<%= render "shared/posts", posts: @offers %>
|
||||
|
||||
<div class="container-fluid offers">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<%= render "shared/posts", posts: @offers %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= paginate @offers %>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<%= show_error_messages!(@organization) %>
|
||||
<%= simple_form_for @organization do |f| %>
|
||||
<%= f.input :name %>
|
||||
<%= f.input :email %>
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
<% if @organization.errors.present? %>
|
||||
<% @organization.errors.full_messages.each do |msg| %>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<%= msg %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<h1>
|
||||
<%= link_to @organization, organization_path(@organization) %>
|
||||
<small><%= t 'global.edit' %></small>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<%= Organization.model_name.human(count: :many) %>
|
||||
</h1>
|
||||
|
||||
<ul class="nav nav-pills">
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<% if superadmin? %>
|
||||
<li>
|
||||
<%= link_to new_organization_path do %>
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
<%= glyph :tag %>
|
||||
<%= link_to tag, get_index_path(post,tag: tag) %>
|
||||
<% end %>
|
||||
<% if post.type == "Inquiry" %>
|
||||
<span class="pull-right">
|
||||
<%= l post.updated_at.to_date, format: :long %>
|
||||
</span>
|
||||
<% end %>
|
||||
</small>
|
||||
</p>
|
||||
|
||||
<% if post.type == "Inquiry" %>
|
||||
<div class="post__datetime">
|
||||
<%= l post.updated_at.to_date, format: :long %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
<th><%= t '.last_movement' %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
<%# Por días sin movimientos %>
|
||||
<% @members.includes(:account)
|
||||
.sort_by(&:days_without_swaps)
|
||||
.reverse
|
||||
.each do |mem| %>
|
||||
<tr>
|
||||
<td><%= mem.member_uid %></td>
|
||||
<td><%= link_to mem.user.username, mem.user %></td>
|
||||
<td><%= mem.days_without_swaps %></td>
|
||||
<td><%= (mem.account.updated_at == mem.account.created_at) ? t(".no_movements") : l(mem.account.updated_at, format: :long) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tbody>
|
||||
<% @members.includes(:account)
|
||||
.sort_by(&:days_without_swaps)
|
||||
.reverse
|
||||
.each do |mem| %>
|
||||
<tr>
|
||||
<td><%= mem.member_uid %></td>
|
||||
<td><%= link_to mem.user.username, mem.user %></td>
|
||||
<td><%= mem.days_without_swaps %></td>
|
||||
<td><%= (mem.account.updated_at == mem.account.created_at) ? t(".no_movements") : l(mem.account.updated_at, format: :long) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,65 +1,83 @@
|
||||
<div>
|
||||
<h1>
|
||||
<%= User.model_name.human.pluralize %>
|
||||
—
|
||||
<%= link_to current_organization.name,
|
||||
organization_path(current_organization) %>
|
||||
</h1>
|
||||
<div class="navbar">
|
||||
<%= search_form_for(@search, class: "navbar-form navbar-left", url: users_path) do |f| %>
|
||||
<%= f.search_field :user_username_or_user_email_or_member_uid_contains, class: "form-control" %>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t 'global.search' %>
|
||||
</button>
|
||||
<% end %>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<% if admin? %>
|
||||
<li>
|
||||
<a href="<%= new_user_path %>">
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
<%= t "helpers.submit.create", model: User.model_name.human %>
|
||||
</a>
|
||||
</li>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1><%= t(".members") %></h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<%= search_form_for(@search, class: "navbar-form navbar-left", url: users_path) do |f| %>
|
||||
<div class="form-group">
|
||||
<%= f.search_field :user_username_or_user_email_or_member_uid_contains, class: "form-control" %>
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">
|
||||
<%= t 'global.search' %>
|
||||
</button>
|
||||
<% end %>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav pull-right">
|
||||
<% if admin? %>
|
||||
<li>
|
||||
<a href="<%= new_user_path %>">
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
<%= t "helpers.submit.create", model: User.model_name.human %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-condensed users panel">
|
||||
<thead>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>
|
||||
<%= sort_link @search, :member_uid, 'ID' %>
|
||||
</th>
|
||||
<th>
|
||||
<%= sort_link @search, :user_username, User.human_attribute_name(:username) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= sort_link @search, :user_email, User.human_attribute_name(:email) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= User.human_attribute_name(:phone) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= User.human_attribute_name(:alt_phone) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= sort_link @search, 'account_balance', Account.human_attribute_name(:balance) %>
|
||||
</th>
|
||||
<% if current_user.manages? current_organization %>
|
||||
<th>
|
||||
<span class="glyphicon glyphicon-hand-down"></span>
|
||||
<%= t(".actions") %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= render "user_rows", members: @member_view_models %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2>
|
||||
<%= link_to current_organization.name,
|
||||
organization_path(current_organization) %>
|
||||
</h2>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-condensed users panel">
|
||||
<thead>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>
|
||||
<%= sort_link @search, :member_uid, 'ID' %>
|
||||
</th>
|
||||
<th>
|
||||
<%= sort_link @search, :user_username, User.human_attribute_name(:username) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= sort_link @search, :user_email, User.human_attribute_name(:email) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= User.human_attribute_name(:phone) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= User.human_attribute_name(:alt_phone) %>
|
||||
</th>
|
||||
<th>
|
||||
<%= sort_link @search, 'account_balance', Account.human_attribute_name(:balance) %>
|
||||
</th>
|
||||
<% if current_user.manages? current_organization %>
|
||||
<th>
|
||||
<span class="glyphicon glyphicon-hand-down"></span>
|
||||
<%= t(".actions") %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= render "user_rows", members: @member_view_models %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @members %>
|
||||
<%= paginate @members %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,5 +32,8 @@ module Timeoverflow
|
||||
# Activate the Skylight agent in staging. You need to provision the
|
||||
# SKYLIGHT_AUTHENTICATION env var for this to work.
|
||||
config.skylight.environments += ["staging"]
|
||||
|
||||
# ActiveJob configuration
|
||||
config.active_job.queue_adapter = :sidekiq
|
||||
end
|
||||
end
|
||||
|
||||
+3
-3
@@ -12,9 +12,10 @@
|
||||
|
||||
defaults: &defaults
|
||||
adapter: postgresql
|
||||
host: <%= ENV['DATABASE_HOST'] %> # default is localhost
|
||||
username: <%= ENV['DATABASE_USER'] %> # default is null
|
||||
password: <%= ENV['DATABASE_PASSWORD'] %> # default is null
|
||||
collation: 'es_ES.UTF-8'
|
||||
ctype: 'es_ES.UTF-8'
|
||||
template: 'template0'
|
||||
encoding: utf8
|
||||
|
||||
development:
|
||||
@@ -23,7 +24,6 @@ development:
|
||||
|
||||
test:
|
||||
<<: *defaults
|
||||
host: localhost
|
||||
database: 'timeoverflow_test'
|
||||
|
||||
staging:
|
||||
|
||||
@@ -44,4 +44,7 @@ Rails.application.configure do
|
||||
|
||||
# Avoid seeing all that stuff in tests
|
||||
config.log_level = :warn
|
||||
|
||||
# ActiveJob configuration
|
||||
config.active_job.queue_adapter = :test
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
schedule_file = 'config/schedule.yml'
|
||||
|
||||
if File.exist?(schedule_file) && Sidekiq.server?
|
||||
Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
|
||||
end
|
||||
@@ -499,6 +499,7 @@ ca:
|
||||
give_time:
|
||||
give_time: Donar Temps a
|
||||
index:
|
||||
members: Membres
|
||||
actions: Accions
|
||||
active_warning: Estàs a punt de canviar l'estat de l'usuari %{username}
|
||||
active_warning_angular: Vas a canviar l'estat del compte de l'usuari {{username}}
|
||||
|
||||
@@ -499,6 +499,7 @@ en:
|
||||
give_time:
|
||||
give_time: Give time to
|
||||
index:
|
||||
members: Members
|
||||
actions: Actions
|
||||
active_warning: You are going to change user account status for %{username}
|
||||
active_warning_angular: You are going to change user account status for {{username}}
|
||||
|
||||
@@ -499,6 +499,7 @@ es:
|
||||
give_time:
|
||||
give_time: Dar Tiempo a
|
||||
index:
|
||||
members: Miembros
|
||||
actions: Acciones
|
||||
active_warning: Estás a punto de cambiar el estado del usuario %{username}
|
||||
active_warning_angular: Va a cambiar el estado de la cuenta del usuario {{username}}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
require 'sidekiq/web'
|
||||
require 'sidekiq/cron/web'
|
||||
|
||||
Rails.application.routes.draw do
|
||||
root to: "home#index"
|
||||
|
||||
authenticate :user, lambda { |u| Rails.env.development? || u.superadmin? } do
|
||||
mount Sidekiq::Web => '/sidekiq'
|
||||
end
|
||||
|
||||
devise_for :users, controllers: { sessions: "sessions" }
|
||||
|
||||
devise_scope :user do
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
:queues:
|
||||
- default
|
||||
- cron
|
||||
@@ -0,0 +1,43 @@
|
||||
# This migration does not use Rails ActiveRecord ORM DSL since
|
||||
# it doesn't provide data integrity (foreign key) for polymorphic models.
|
||||
#
|
||||
# The technique applied is called Exclusive Belongs To (AKA Exclusive Arc)
|
||||
#
|
||||
# Please read the following article for more details:
|
||||
# https://hashrocket.com/blog/posts/modeling-polymorphic-associations-in-a-relational-database
|
||||
#
|
||||
class CreateEvents < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :events do |t|
|
||||
t.integer :action, null:false
|
||||
t.integer :post_id
|
||||
t.integer :member_id
|
||||
t.integer :transfer_id
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_foreign_key :events, :posts, name: 'events_post_id_fkey'
|
||||
add_foreign_key :events, :members, name: 'events_member_id_fkey'
|
||||
add_foreign_key :events, :transfers, name: 'events_transfer_id_fkey'
|
||||
|
||||
add_index :events, :post_id, unique: true, where: 'post_id IS NOT NULL'
|
||||
add_index :events, :member_id, unique: true, where: 'member_id IS NOT NULL'
|
||||
add_index :events, :transfer_id, unique: true, where: 'transfer_id IS NOT NULL'
|
||||
|
||||
execute <<-SQL
|
||||
ALTER TABLE events
|
||||
ADD CHECK(action IN (0, 1)),
|
||||
ADD CHECK(
|
||||
(
|
||||
(post_id IS NOT NULL)::integer +
|
||||
(member_id IS NOT NULL)::integer +
|
||||
(transfer_id IS NOT NULL)::integer
|
||||
) = 1
|
||||
);
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :events
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
class ChangeOrganizationsNameConstraints < ActiveRecord::Migration
|
||||
def up
|
||||
change_column_null :organizations, :name, false
|
||||
add_index :organizations, :name, unique: true
|
||||
end
|
||||
|
||||
def down
|
||||
change_column_null :organizations, :name, true
|
||||
remove_index :organizations, :name
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
class CreatePushNotifications < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :push_notifications do |t|
|
||||
t.references :event, null: false
|
||||
t.references :device_token, null: false
|
||||
t.datetime :processed_at
|
||||
|
||||
t.timestamps null: false
|
||||
end
|
||||
|
||||
add_foreign_key :push_notifications, :events
|
||||
add_foreign_key :push_notifications, :device_tokens
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class RemovePasswordDigestFromUser < ActiveRecord::Migration
|
||||
def up
|
||||
remove_column :users, :password_digest
|
||||
end
|
||||
|
||||
def down
|
||||
add_column :users, :password_digest, :string
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
class ChangeIndexOnEvents < ActiveRecord::Migration
|
||||
def change
|
||||
remove_index :events, :post_id
|
||||
remove_index :events, :member_id
|
||||
remove_index :events, :transfer_id
|
||||
|
||||
add_index :events, :post_id, where: 'post_id IS NOT NULL'
|
||||
add_index :events, :member_id, where: 'member_id IS NOT NULL'
|
||||
add_index :events, :transfer_id, where: 'transfer_id IS NOT NULL'
|
||||
end
|
||||
end
|
||||
+30
-3
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
ActiveRecord::Schema.define(version: 20180529144243) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -76,6 +76,19 @@ ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
add_index "documents", ["documentable_id", "documentable_type"], name: "index_documents_on_documentable_id_and_documentable_type", using: :btree
|
||||
add_index "documents", ["label"], name: "index_documents_on_label", using: :btree
|
||||
|
||||
create_table "events", force: :cascade do |t|
|
||||
t.integer "action", null: false
|
||||
t.integer "post_id"
|
||||
t.integer "member_id"
|
||||
t.integer "transfer_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "events", ["member_id"], name: "index_events_on_member_id", where: "(member_id IS NOT NULL)", using: :btree
|
||||
add_index "events", ["post_id"], name: "index_events_on_post_id", where: "(post_id IS NOT NULL)", using: :btree
|
||||
add_index "events", ["transfer_id"], name: "index_events_on_transfer_id", where: "(transfer_id IS NOT NULL)", using: :btree
|
||||
|
||||
create_table "members", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "organization_id"
|
||||
@@ -102,7 +115,7 @@ ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
add_index "movements", ["transfer_id"], name: "index_movements_on_transfer_id", using: :btree
|
||||
|
||||
create_table "organizations", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.string "name", limit: 255, null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "reg_number_seq"
|
||||
@@ -118,6 +131,8 @@ ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
t.string "domain"
|
||||
end
|
||||
|
||||
add_index "organizations", ["name"], name: "index_organizations_on_name", unique: true, using: :btree
|
||||
|
||||
create_table "posts", force: :cascade do |t|
|
||||
t.string "title"
|
||||
t.string "type"
|
||||
@@ -143,6 +158,14 @@ ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
add_index "posts", ["tags"], name: "index_posts_on_tags", using: :gin
|
||||
add_index "posts", ["user_id"], name: "index_posts_on_user_id", using: :btree
|
||||
|
||||
create_table "push_notifications", force: :cascade do |t|
|
||||
t.integer "event_id", null: false
|
||||
t.integer "device_token_id", null: false
|
||||
t.datetime "processed_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "transfers", force: :cascade do |t|
|
||||
t.integer "post_id"
|
||||
t.text "reason"
|
||||
@@ -162,7 +185,6 @@ ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "username", null: false
|
||||
t.string "email", null: false
|
||||
t.string "password_digest"
|
||||
t.date "date_of_birth"
|
||||
t.string "identity_document"
|
||||
t.string "phone"
|
||||
@@ -198,4 +220,9 @@ ActiveRecord::Schema.define(version: 20180221161343) do
|
||||
add_index "users", ["email"], name: "index_users_on_email", using: :btree
|
||||
|
||||
add_foreign_key "accounts", "organizations"
|
||||
add_foreign_key "events", "members", name: "events_member_id_fkey"
|
||||
add_foreign_key "events", "posts", name: "events_post_id_fkey"
|
||||
add_foreign_key "events", "transfers", name: "events_transfer_id_fkey"
|
||||
add_foreign_key "push_notifications", "device_tokens"
|
||||
add_foreign_key "push_notifications", "events"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Fabricator(:device_token) do
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
Fabricator(:event) do
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
Fabricator(:transfer) do
|
||||
source { Fabricate(:account) }
|
||||
destination { Fabricate(:account) }
|
||||
amount 10
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe CreatePushNotificationsJob, type: :job do
|
||||
describe '#perform' do
|
||||
context 'with an Event that doesn\'t exist' do
|
||||
let(:event_id) { nil }
|
||||
|
||||
it 'raises an error' do
|
||||
expect {
|
||||
described_class.new.perform(event_id: event_id)
|
||||
}.to raise_error 'A valid Event must be provided'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an Event that does exist' do
|
||||
let(:post) { Fabricate(:post) }
|
||||
let(:event) { Fabricate(:event, post: post, action: :created) }
|
||||
let(:event_id) { event.id }
|
||||
|
||||
it 'calls the PushNotification creator' do
|
||||
creator = instance_double(::PushNotifications::Creator)
|
||||
expect(::PushNotifications::Creator).to receive(:new)
|
||||
.with(event: event)
|
||||
.and_return(creator)
|
||||
expect(creator).to receive(:create!)
|
||||
|
||||
described_class.new.perform(event_id: event_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Event do
|
||||
describe 'Validations' do
|
||||
it { is_expected.to validate_presence_of(:action) }
|
||||
it do
|
||||
is_expected.to define_enum_for(:action)
|
||||
.with([:created, :updated])
|
||||
end
|
||||
|
||||
describe '#resource_presence validation' do
|
||||
let(:post) { Fabricate(:post) }
|
||||
let(:member) { Fabricate(:member) }
|
||||
let(:event) { Event.new action: 'created' }
|
||||
|
||||
context 'has no resources' do
|
||||
it { expect(event).to_not be_valid }
|
||||
end
|
||||
|
||||
context 'has one resource' do
|
||||
before { event.post = post }
|
||||
|
||||
it { expect(event).to be_valid }
|
||||
end
|
||||
|
||||
context 'has two resources' do
|
||||
before { event.post = post; event.member = member }
|
||||
|
||||
it { expect(event).to_not be_valid }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Relations' do
|
||||
it { is_expected.to belong_to(:post) }
|
||||
it { is_expected.to belong_to(:member) }
|
||||
it { is_expected.to belong_to(:transfer) }
|
||||
|
||||
it { is_expected.to have_db_column(:post_id) }
|
||||
it { is_expected.to have_db_column(:member_id) }
|
||||
it { is_expected.to have_db_column(:transfer_id) }
|
||||
end
|
||||
|
||||
describe 'Indexes' do
|
||||
it { is_expected.to have_db_index(:post_id) }
|
||||
it { is_expected.to have_db_index(:member_id) }
|
||||
it { is_expected.to have_db_index(:transfer_id) }
|
||||
end
|
||||
end
|
||||
@@ -17,35 +17,48 @@ describe Organization do
|
||||
end
|
||||
end
|
||||
|
||||
it "1: without http & https" do
|
||||
organization.web = "www.casa.com"
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq "http://www.casa.com"
|
||||
describe 'ensure_url validation' do
|
||||
it "without http & https" do
|
||||
organization.web = "www.casa.com"
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq "http://www.casa.com"
|
||||
end
|
||||
|
||||
it "with http" do
|
||||
organization.web = "http://www.casa.com"
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq "http://www.casa.com"
|
||||
end
|
||||
|
||||
it "with https" do
|
||||
organization.web = "https://www.casa.com"
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq "https://www.casa.com"
|
||||
end
|
||||
|
||||
it "with blank value" do
|
||||
organization.web = ""
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq ""
|
||||
end
|
||||
|
||||
it "with nil value" do
|
||||
organization.web = nil
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq nil
|
||||
end
|
||||
|
||||
it "with an invalid" do
|
||||
organization.web = "la casa"
|
||||
expect(organization).not_to be_valid
|
||||
expect(organization.web).to eq "la casa"
|
||||
expect(organization.errors.size).to eq 1
|
||||
end
|
||||
end
|
||||
it "2: with http" do
|
||||
organization.web = "http://www.casa.com"
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq "http://www.casa.com"
|
||||
end
|
||||
it "3: with https" do
|
||||
organization.web = "https://www.casa.com"
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq "https://www.casa.com"
|
||||
end
|
||||
it "4: blank" do
|
||||
organization.web = ""
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq ""
|
||||
end
|
||||
it "5: nil" do
|
||||
organization.web = ""
|
||||
expect(organization).to be_valid
|
||||
expect(organization.web).to eq ""
|
||||
end
|
||||
it "6: no url" do
|
||||
organization.web = "la casa"
|
||||
expect(organization).not_to be_valid
|
||||
expect(organization.web).to eq "la casa"
|
||||
expect(organization.errors.size).to eq 1
|
||||
|
||||
it 'name is mandatory' do
|
||||
organization.name = nil
|
||||
organization.save
|
||||
expect(organization.errors[:name]).to include(I18n.t('errors.messages.blank'))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe PushNotification do
|
||||
describe 'Validations' do
|
||||
it { is_expected.to validate_presence_of(:event) }
|
||||
it { is_expected.to validate_presence_of(:device_token) }
|
||||
end
|
||||
|
||||
describe 'Associations' do
|
||||
it { is_expected.to belong_to(:event).with_foreign_key('event_id') }
|
||||
it { is_expected.to belong_to(:device_token).with_foreign_key('device_token_id') }
|
||||
|
||||
it { is_expected.to have_db_column(:event_id) }
|
||||
it { is_expected.to have_db_column(:device_token_id) }
|
||||
end
|
||||
end
|
||||
@@ -3,15 +3,32 @@ require 'spec_helper'
|
||||
describe Persister::MemberPersister do
|
||||
let(:organization) { Fabricate(:organization) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:member) { Fabricate.build(:member, user: user, organization: organization) }
|
||||
let(:persister) { ::Persister::MemberPersister.new(member) }
|
||||
|
||||
describe '#save' do
|
||||
before { persister.save }
|
||||
|
||||
it 'saves the member' do
|
||||
member = Member.new(user: user, organization: organization)
|
||||
|
||||
persister = ::Persister::MemberPersister.new(member)
|
||||
persister.save
|
||||
|
||||
expect(member).to be_persisted
|
||||
end
|
||||
|
||||
# TODO: write better expectation
|
||||
it 'creates an event' do
|
||||
expect(Event.where(member_id: member.id).first.action).to eq('created')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_attributes' do
|
||||
before { persister.update_attributes(member_uid: 666) }
|
||||
|
||||
it 'updates the resource attributes' do
|
||||
expect(member.member_uid).to eq(666)
|
||||
end
|
||||
|
||||
# TODO: write better expectation
|
||||
it 'creates an event' do
|
||||
expect(Event.where(member_id: member.id).first.action).to eq('updated')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,28 +1,70 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Persister::PostPersister do
|
||||
RSpec.describe Persister::PostPersister do
|
||||
let(:organization) { Fabricate(:organization) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:category) { Fabricate(:category) }
|
||||
let(:post) { Fabricate(:post, organization: organization) }
|
||||
let(:post) do
|
||||
Fabricate.build(
|
||||
:offer,
|
||||
organization: organization,
|
||||
user: user,
|
||||
category: category,
|
||||
title: 'Title'
|
||||
)
|
||||
end
|
||||
let(:persister) { ::Persister::PostPersister.new(post) }
|
||||
let(:event) { Fabricate.build(:event, id: 27) }
|
||||
|
||||
describe '#save' do
|
||||
it 'saves the post' do
|
||||
post = Offer.new(organization: organization, user: user, category: category, title: 'Title')
|
||||
persister = ::Persister::PostPersister.new(post)
|
||||
|
||||
persister.save
|
||||
|
||||
expect(post).to be_persisted
|
||||
end
|
||||
|
||||
it 'creates an event' do
|
||||
expect(::Event).to receive(:create!).with(action: :created, post: post).and_return(event)
|
||||
|
||||
persister.save
|
||||
end
|
||||
|
||||
context 'background job' do
|
||||
before do
|
||||
allow(::Event).to receive(:create!).and_return(event)
|
||||
end
|
||||
|
||||
it 'enqueues a CreatePushNotificationsJob background job' do
|
||||
expect {
|
||||
persister.save
|
||||
}.to enqueue_job(CreatePushNotificationsJob).with(event_id: 27)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_attributes' do
|
||||
it 'updates the attributes' do
|
||||
persister = ::Persister::PostPersister.new(post)
|
||||
it 'updates the resource attributes' do
|
||||
persister.update_attributes(title: 'New title')
|
||||
|
||||
expect(post.title).to eq('New title')
|
||||
end
|
||||
|
||||
it 'creates an event' do
|
||||
expect(::Event).to receive(:create!).with(action: :updated, post: post).and_return(event)
|
||||
|
||||
persister.update_attributes(title: 'New title')
|
||||
end
|
||||
|
||||
context 'background job' do
|
||||
before do
|
||||
allow(::Event).to receive(:create!).and_return(event)
|
||||
end
|
||||
|
||||
it 'enqueues a CreatePushNotificationsJob background job' do
|
||||
expect {
|
||||
persister.update_attributes(title: 'New title')
|
||||
}.to enqueue_job(CreatePushNotificationsJob).with(event_id: 27)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,15 +5,39 @@ describe Persister::TransferPersister do
|
||||
let(:destination_account) { Fabricate(:account) }
|
||||
let(:organization) { Fabricate(:organization) }
|
||||
let(:post) { Fabricate(:post, organization: organization) }
|
||||
let(:transfer) do
|
||||
Fabricate.build(
|
||||
:transfer,
|
||||
post: post,
|
||||
source: source_account,
|
||||
destination: destination_account
|
||||
)
|
||||
end
|
||||
let(:persister) { ::Persister::TransferPersister.new(transfer) }
|
||||
|
||||
describe '#save' do
|
||||
before { persister.save }
|
||||
|
||||
it 'saves the transfer' do
|
||||
transfer = Transfer.new(post: post, source: source_account, destination: destination_account)
|
||||
|
||||
persister = ::Persister::TransferPersister.new(transfer)
|
||||
persister.save
|
||||
|
||||
expect(transfer).to be_persisted
|
||||
end
|
||||
|
||||
# TODO: write better expectation
|
||||
it 'creates an event' do
|
||||
expect(Event.where(transfer_id: transfer.id).first.action).to eq('created')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_attributes' do
|
||||
before { persister.update_attributes(amount: 666) }
|
||||
|
||||
it 'updates the resource attributes' do
|
||||
expect(transfer.amount).to eq(666)
|
||||
end
|
||||
|
||||
# TODO: write better expectation
|
||||
it 'creates an event' do
|
||||
expect(Event.where(transfer_id: transfer.id).first.action).to eq('updated')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe PushNotifications::Creator do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let!(:device_token) { Fabricate(:device_token, user: user, token: 'aloha') }
|
||||
let(:organization) { Fabricate(:organization) }
|
||||
let(:post) { Fabricate(:post, organization: organization, user: user) }
|
||||
let(:event) { Fabricate.build(:event, post: post, action: :created) }
|
||||
let(:creator) { described_class.new(event: event) }
|
||||
|
||||
before do
|
||||
organization.members.create(user: user)
|
||||
end
|
||||
|
||||
describe '#create!' do
|
||||
it 'creates as many PushNotification resources as needed' do
|
||||
expect(PushNotification).to receive(:create!).with(
|
||||
event: event,
|
||||
device_token: device_token
|
||||
).once
|
||||
|
||||
creator.create!
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ::PushNotifications::EventNotifier::Post do
|
||||
let(:user) { Fabricate.build(:user) }
|
||||
let(:organization) { Fabricate(:organization) }
|
||||
let(:post) { Fabricate(:post, organization: organization, user: user) }
|
||||
let(:event) { Fabricate.build(:event, post: post, action: :created) }
|
||||
|
||||
describe '#users' do
|
||||
context 'when a user pertains to the Post\'s organization' do
|
||||
before { organization.members.create(user: user) }
|
||||
|
||||
context 'and the user has a DeviceToken associated' do
|
||||
let!(:device_token) { Fabricate(:device_token, user: user, token: 'aloha') }
|
||||
|
||||
it 'returns the device token associated with the user' do
|
||||
expect(described_class.new(event: event).device_tokens).to eq([device_token])
|
||||
end
|
||||
end
|
||||
|
||||
context 'but the user has no DeviceToken associated' do
|
||||
it 'doesn\'t return the user' do
|
||||
expect(described_class.new(event: event).device_tokens).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a user doesn\'t pertain to the Post\'s organization' do
|
||||
let(:other_user) { Fabricate(:user) }
|
||||
let!(:device_token) { Fabricate(:device_token, user: other_user, token: 'WAT') }
|
||||
|
||||
it 'doesn\'t return the user' do
|
||||
expect(described_class.new(event: event).device_tokens).to_not include(device_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe PushNotifications::EventNotifierFactory do
|
||||
describe '#build' do
|
||||
let(:user) { Fabricate.build(:user) }
|
||||
let(:organization) { Fabricate(:organization) }
|
||||
let(:factory) { described_class.new(event: event) }
|
||||
|
||||
context 'when the given Event is associated to a Post' do
|
||||
let(:post) { Fabricate(:post, organization: organization, user: user) }
|
||||
let(:event) { Fabricate.build(:event, post: post, action: :created) }
|
||||
|
||||
it 'returns a Post notifier' do
|
||||
notifier = instance_double(::PushNotifications::EventNotifier::Post)
|
||||
allow(::PushNotifications::EventNotifier::Post).to receive(:new).and_return(notifier)
|
||||
|
||||
expect(factory.build).to be(notifier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the given Event is associated to a resource not supported' do
|
||||
let(:event) { Fabricate.build(:event, action: :created) }
|
||||
|
||||
it 'raises an error' do
|
||||
expect {
|
||||
factory.build
|
||||
}.to raise_error('The resource associated to the Event is not supported')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,7 @@ require 'database_cleaner'
|
||||
require 'fabrication'
|
||||
require 'selenium/webdriver'
|
||||
require 'faker'
|
||||
require 'shoulda/matchers'
|
||||
I18n.reload!
|
||||
|
||||
Capybara.register_driver :chrome do |app|
|
||||
@@ -149,3 +150,10 @@ RSpec.shared_context 'stub browser locale' do
|
||||
end
|
||||
|
||||
RSpec.configure(&:infer_spec_type_from_file_location!)
|
||||
|
||||
Shoulda::Matchers.configure do |config|
|
||||
config.integrate do |with|
|
||||
with.test_framework :rspec
|
||||
with.library :rails
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user