Compare commits

..

6 commits

Author SHA1 Message Date
Devin Howard
e0eb3e6333 fix pathname 2017-09-23 11:57:57 -07:00
Devin Howard
6bbd35d644 cache path name to avoid race conditions when updating url 2017-09-23 11:57:57 -07:00
Devin Howard
d219bde48d rework debouncing and lodash in Visualize.js 2017-09-23 11:57:57 -07:00
Devin Howard
e30d05f71d fix initial scale/translate algorithm 2017-09-23 11:57:57 -07:00
Devin Howard
7af5972765 monkey patch scale/translate functions so they update the URL 2017-09-23 11:57:57 -07:00
Devin Howard
75e41619eb enable specifying scale/translate in query params for a map
e.g. https://metamaps.cc/maps/12?scale=0.5&translate=-350,300
2017-09-23 11:57:57 -07:00
294 changed files with 1189 additions and 2278 deletions

View file

@ -12,7 +12,7 @@ Rails:
Enabled: true Enabled: true
Metrics/LineLength: Metrics/LineLength:
Max: 120 Max: 100
Metrics/AbcSize: Metrics/AbcSize:
Max: 16 Max: 16
@ -22,8 +22,3 @@ Style/Documentation:
Style/EmptyMethod: Style/EmptyMethod:
EnforcedStyle: expanded EnforcedStyle: expanded
# I like this cop, but occasionally code is more readable without a guard clause,
# and I don't want to write rubocop:disable comments every time that happens
Style/GuardClause:
Enabled: false

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
source 'https://rubygems.org' source 'https://rubygems.org'
ruby '2.3.0' ruby '2.3.0'
@ -38,7 +37,7 @@ gem 'uglifier'
group :test do group :test do
gem 'brakeman', require: false gem 'brakeman', require: false
gem 'factory_bot_rails' gem 'factory_girl_rails'
gem 'json-schema' gem 'json-schema'
gem 'rspec-rails' gem 'rspec-rails'
gem 'shoulda-matchers' gem 'shoulda-matchers'
@ -48,10 +47,10 @@ end
group :development, :test do group :development, :test do
gem 'better_errors' gem 'better_errors'
gem 'binding_of_caller' gem 'binding_of_caller'
gem 'faker'
gem 'pry-byebug' gem 'pry-byebug'
gem 'pry-rails' gem 'pry-rails'
gem 'rubocop', '~> 0.48.1' # match code climate https://github.com/tootsuite/mastodon/issues/1758 gem 'rubocop'
gem 'timecop'
gem 'tunemygc' gem 'tunemygc'
gem 'faker'
gem 'timecop'
end end

View file

@ -105,10 +105,10 @@ GEM
actionmailer (>= 4.0, < 6) actionmailer (>= 4.0, < 6)
activesupport (>= 4.0, < 6) activesupport (>= 4.0, < 6)
execjs (2.7.0) execjs (2.7.0)
factory_bot (4.8.2) factory_girl (4.8.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
factory_bot_rails (4.8.2) factory_girl_rails (4.8.0)
factory_bot (~> 4.8.2) factory_girl (~> 4.8.0)
railties (>= 3.0.0) railties (>= 3.0.0)
faker (1.8.4) faker (1.8.4)
i18n (~> 0.5) i18n (~> 0.5)
@ -117,8 +117,7 @@ GEM
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
httparty (0.15.6) httparty (0.15.6)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (0.9.3) i18n (0.8.6)
concurrent-ruby (~> 1.0)
jmespath (1.3.1) jmespath (1.3.1)
jquery-rails (4.3.1) jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
@ -154,21 +153,22 @@ GEM
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521) mime-types-data (3.2016.0521)
mimemagic (0.3.2) mimemagic (0.3.2)
mini_portile2 (2.3.0) mini_portile2 (2.2.0)
minitest (5.11.1) minitest (5.10.3)
multi_xml (0.6.0) multi_xml (0.6.0)
nio4r (2.1.0) nio4r (2.1.0)
nokogiri (1.8.1) nokogiri (1.8.0)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.2.0)
orm_adapter (0.5.0) orm_adapter (0.5.0)
paperclip (5.2.0) paperclip (5.1.0)
activemodel (>= 4.2.0) activemodel (>= 4.2.0)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
cocaine (~> 0.5.5) cocaine (~> 0.5.5)
mime-types mime-types
mimemagic (~> 0.3.0) mimemagic (~> 0.3.0)
parser (2.4.0.2) parallel (1.12.0)
ast (~> 2.3) parser (2.4.0.0)
ast (~> 2.2)
pg (0.21.0) pg (0.21.0)
powerpack (0.1.1) powerpack (0.1.1)
pry (0.10.4) pry (0.10.4)
@ -216,7 +216,7 @@ GEM
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.2.2) rainbow (2.2.2)
rake rake
rake (12.3.0) rake (12.0.0)
rb-fsevent (0.10.2) rb-fsevent (0.10.2)
rb-inotify (0.9.10) rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2) ffi (>= 0.5.0, < 2)
@ -241,13 +241,14 @@ GEM
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.6.0)
rspec-support (3.6.0) rspec-support (3.6.0)
rubocop (0.48.1) rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0) parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1) unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.9.0) ruby-progressbar (1.8.1)
sass (3.5.1) sass (3.5.1)
sass-listen (~> 4.0.0) sass-listen (~> 4.0.0)
sass-listen (4.0.0) sass-listen (4.0.0)
@ -284,7 +285,7 @@ GEM
tilt (2.0.8) tilt (2.0.8)
timecop (0.9.1) timecop (0.9.1)
tunemygc (1.0.69) tunemygc (1.0.69)
tzinfo (1.2.4) tzinfo (1.2.3)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (3.2.0) uglifier (3.2.0)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
@ -311,7 +312,7 @@ DEPENDENCIES
doorkeeper doorkeeper
dotenv-rails dotenv-rails
exception_notification exception_notification
factory_bot_rails factory_girl_rails
faker faker
httparty httparty
jquery-rails jquery-rails
@ -332,7 +333,7 @@ DEPENDENCIES
rails (~> 5.0.0) rails (~> 5.0.0)
redis (~> 3.3.3) redis (~> 3.3.3)
rspec-rails rspec-rails
rubocop (~> 0.48.1) rubocop
sass-rails sass-rails
shoulda-matchers shoulda-matchers
simplecov simplecov
@ -347,4 +348,4 @@ RUBY VERSION
ruby 2.3.0p0 ruby 2.3.0p0
BUNDLED WITH BUNDLED WITH
1.16.1 1.15.4

1
Rakefile Executable file → Normal file
View file

@ -1,6 +1,5 @@
#!/usr/bin/env rake #!/usr/bin/env rake
# frozen_string_literal: true # frozen_string_literal: true
# Add your own tasks in files placed in lib/tasks ending in .rake, # Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

View file

@ -56,15 +56,16 @@
} }
li.toggledOff { li.toggledOff {
opacity: 0.6; opacity: 0.4;
} }
} }
.centerContent { .blackBox {
width: 760px; width: 760px;
margin: 0 auto; margin: 0 auto;
padding: 80px 0 60px 20px; padding: 80px 0 60px 20px;
background: rgba(125, 125, 125, 0.4); background: rgba(0, 0, 0, 0.4);
color: white;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
@ -84,10 +85,10 @@
display: table-row; display: table-row;
} }
tr:nth-child(odd) { tr:nth-child(odd) {
background: rgba(125, 125, 125, 0.2); background: rgba(0, 0, 0, 0.2);
} }
tr:nth-child(even) { tr:nth-child(even) {
background: rgba(125, 125, 125, 0.3); background: rgba(0, 0, 0, 0.3);
} }
th, th,
td { td {

View file

@ -826,7 +826,6 @@ label {
font-size: 14px; font-size: 14px;
line-height: 14px; line-height: 14px;
color: #757575; color: #757575;
cursor: pointer;
} }
.accountListItem:hover { .accountListItem:hover {
color: #424242; color: #424242;
@ -2930,6 +2929,136 @@ and it won't be important on password protected instances */
color: #424242; color: #424242;
} }
/* Admin Pages */
.blackBox {
width: 760px;
margin: 0 auto;
padding: 20px 0 60px 20px;
background: rgba(0, 0, 0, 0.4);
color: white;
overflow: hidden;
position: relative;
}
.blackBox .metacodeSetsDescription {
width: 314px;
}
.blackBox td.metacodeSetDesc {
width: 314px;
word-wrap: break-word;
}
.blackBox .metacodeSetImage {
width: 36px;
height: 36px;
float: left;
}
.blackBox tr {
display: table-row;
}
.blackBox tr:nth-child(odd) {
background: rgba(0, 0, 0, 0.2);
}
.blackBox tr:nth-child(even) {
background: rgba(0, 0, 0, 0.3);
}
.blackBox th,
.blackBox td {
padding: 10px;
}
.blackBox td.iconURL {
max-width: 415px;
word-wrap: break-word;
}
.blackBox td.iconColor {
}
.blackBox .field {
margin: 15px 0 5px;
}
.blackBox label {
float: left;
width: 100px;
margin-right: 15px;
}
.blackBox input[type="text"] {
width: 336px;
height: 32px;
font-size: 15px;
direction: ltr;
-webkit-appearance: none;
appearance: none;
display: inline-block;
margin: 0;
padding: 0 8px;
background: #fff;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 1px;
-moz-border-radius: 1px;
border-radius: 1px;
font: -webkit-small-control;
color: initial;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
display: inline-block;
text-align: start;
font-family: arial;
}
.blackBox input[type="text"]:hover,
.blackBox textarea:hover {
border: 1px solid #b9b9b9;
border-top: 1px solid #a0a0a0;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
.blackBox textarea {
padding: 8px;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
resize: none;
font: -webkit-small-control;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
text-align: start;
font-family: arial;
font-size: 15px;
line-height: 17px;
width: 318px;
}
.blackBox .allMetacodes {
padding: 5px 0;
}
.blackBox a.button {
margin-right: 20px;
line-height: 40px;
}
.blackBox a.button,
.blackBox input.add {
float: left;
margin-top: 5px;
height: 40px;
font-size: 17px;
width: auto;
padding: 0 30px;
cursor: pointer;
font-weight: normal;
}
.blackBox a.button:hover,
.blackBox input.add:hover {
-webkit-box-shadow: none;
box-shadow: none;
}
/* request */ /* request */
.requestInvite { .requestInvite {

View file

@ -127,10 +127,6 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
a.mdSupport { a.mdSupport {
color: #4fb5c0; color: #4fb5c0;
font-size: 11px; font-size: 11px;
display: none;
}
.riek-editing + .mdSupport {
display: block;
} }
} }
.CardOnGraph.hasAttachment .scroll { .CardOnGraph.hasAttachment .scroll {

View file

@ -668,19 +668,19 @@
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16); box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
} }
#navBar { #exploreMapsHeader {
position: absolute; position: absolute;
width: 100%; width: 100%;
} }
.navBarContainer { .exploreMapsBar {
z-index:2; z-index:2;
background-color:#FAFAFA; background-color:#FAFAFA;
height: 42px; height: 42px;
padding-top: 52px; padding-top: 52px;
} }
.navBarMenu { .exploreMapsMenu {
display: block; display: block;
width: 100%; width: 100%;
height:42px; height:42px;
@ -689,29 +689,30 @@
text-align: center; text-align: center;
} }
.navBarCenter { .exploreMapsCenter {
display: block; display: block;
} }
.navBarButton { .exploreMapsButton {
color: #757575; color: #757575;
cursor: default; cursor: default;
font-weight: normal; font-weight: normal;
font-family: 'din-medium'; font-family: 'din-medium';
font-size: 14px; font-size: 14px;
padding: 0 8px; height: 14px;
border-bottom: 2px solid rgba(0,0,0,0); padding: 14px 8px 12px 40px;
border-bottom: 2px solid rgba(0,0,0,0);
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
position:relative; position:relative;
} }
.navBarButton:hover, .navBarButton.active { .exploreMapsButton:hover, .exploreMapsButton.active {
text-decoration: none; text-decoration: none;
color: #424242; color: #424242;
border-bottom: 2px solid #00BCD4; border-bottom: 2px solid #00BCD4;
} }
.navBarButton.mapperButton { .exploreMapsButton.mapperButton {
height: 40px; height: 40px;
padding: 0; padding: 0;
} }
@ -728,69 +729,62 @@
} }
.navBarButton .navBarIcon { .exploreMapsButton .exploreMapsIcon {
background-repeat: no-repeat; background-repeat: no-repeat;
width:32px; width:32px;
height:32px; height:32px;
margin-top:5px; position:absolute;
margin-left:5px; top:5px;
margin-right: 5px; left:5px;
display: inline-block;
vertical-align: top;
} }
.navBarLinkText { .exploreMapsCenter .authedApps .exploreMapsIcon {
padding: 11px 0 12px 0;
display: inline-block;
}
.navBarCenter .authedApps .navBarIcon {
background-image: url(<%= asset_path('user_sprite.png') %>); background-image: url(<%= asset_path('user_sprite.png') %>);
background-position: 0 -32px; background-position: 0 -32px;
} }
.navBarCenter .myMaps .navBarIcon { .exploreMapsCenter .myMaps .exploreMapsIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>); background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -32px 0; background-position: -32px 0;
} }
.navBarCenter .sharedMaps .navBarIcon { .exploreMapsCenter .sharedMaps .exploreMapsIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>); background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -128px 0; background-position: -128px 0;
} }
.navBarCenter .activeMaps .navBarIcon { .exploreMapsCenter .activeMaps .exploreMapsIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>); background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: 0 0; background-position: 0 0;
} }
.navBarCenter .featuredMaps .navBarIcon { .exploreMapsCenter .featuredMaps .exploreMapsIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>); background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -96px 0; background-position: -96px 0;
} }
.navBarCenter .starredMaps .navBarIcon { .exploreMapsCenter .starredMaps .exploreMapsIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>); background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -96px 0; background-position: -96px 0;
} }
.navBarCenter .notificationsLink .navBarIcon { .exploreMapsCenter .notificationsLink .exploreMapsIcon {
background-image: url(<%= asset_path 'topright_sprite.png' %>); background-image: url(<%= asset_path 'topright_sprite.png' %>);
background-position: -128px 0; background-position: -128px 0;
} }
.authedApps:hover .navBarIcon, .authedApps.active .navBarIcon { .authedApps:hover .exploreMapsIcon, .authedApps.active .exploreMapsIcon {
background-position-x: -32px; background-position-x: -32px;
} }
.myMaps:hover .navBarIcon, .myMaps.active .navBarIcon { .myMaps:hover .exploreMapsIcon, .myMaps.active .exploreMapsIcon {
background-position: -32px -32px; background-position: -32px -32px;
} }
.activeMaps:hover .navBarIcon, .activeMaps.active .navBarIcon { .activeMaps:hover .exploreMapsIcon, .activeMaps.active .exploreMapsIcon {
background-position: 0 -32px; background-position: 0 -32px;
} }
.featuredMaps:hover .navBarIcon, .featuredMaps.active .navBarIcon { .featuredMaps:hover .exploreMapsIcon, .featuredMaps.active .exploreMapsIcon {
background-position: -96px -32px; background-position: -96px -32px;
} }
.starredMaps:hover .navBarIcon, .starredMaps.active .navBarIcon { .starredMaps:hover .exploreMapsIcon, .starredMaps.active .exploreMapsIcon {
background-position: -96px -32px; background-position: -96px -32px;
} }
.sharedMaps:hover .navBarIcon, .sharedMaps.active .navBarIcon { .sharedMaps:hover .exploreMapsIcon, .sharedMaps.active .exploreMapsIcon {
background-position: -128px -32px; background-position: -128px -32px;
} }
.notificationsLink:hover .navBarIcon, .notificationsLink.active .navBarIcon { .notificationsLink:hover .exploreMapsIcon, .notificationsLink.active .exploreMapsIcon {
background-position-y: -32px; background-position-y: -32px;
} }

View file

@ -32,7 +32,7 @@
/* Smartphones (portrait and landscape) ----------- the minimum space that two map cards can fit side by side */ /* Smartphones (portrait and landscape) ----------- the minimum space that two map cards can fit side by side */
@media only screen and (max-width : 504px) { @media only screen and (max-width : 504px) {
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .feedback-icon, .chat-box, #navBar { .upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .feedback-icon, .chat-box, #exploreMapsHeader {
display: none !important; display: none !important;
} }

View file

@ -1,7 +1,4 @@
$notifications-border-color: #DDDDDD;
$notifications-hover-color: #F6F6F6;
$unread_notifications_dot_size: 8px; $unread_notifications_dot_size: 8px;
.unread-notifications-dot { .unread-notifications-dot {
width: $unread_notifications_dot_size; width: $unread_notifications_dot_size;
height: $unread_notifications_dot_size; height: $unread_notifications_dot_size;
@ -16,72 +13,13 @@ $unread_notifications_dot_size: 8px;
.notificationsIcon { .notificationsIcon {
position: relative; position: relative;
} }
.notificationsBox {
position: absolute;
background: #FFFFFF;
border-radius: 2px;
width: 350px;
right: 0;
top: 50px;
box-shadow: 0 3px 6px rgba(0,0,0,0.16);
border: 1px solid $notifications-border-color;
.notificationsBoxTriangle {
min-width: 0 !important;
display: block;
position: absolute;
right: 48px;
width: 20px !important;
height: 20px !important;
margin-left: -10px;
top: -11px;
border-left: 1px solid $notifications-border-color;
border-top: 1px solid $notifications-border-color;
border-bottom: 0 !important;
border-right: 0 !important;
background-color: #fff;
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
}
ul.notifications {
max-height: 500px;
overflow-y: auto;
.notification {
font-size: 13px;
.notification-body {
border-bottom: 1px solid $notifications-border-color;
}
}
.notificationsEmpty {
font-family: din-regular, helvetica, sans-serif;
margin: 50px 10px;
text-align: center;
}
}
.notificationsBoxSeeAll {
display: block;
width: 100%;
text-align: center;
padding: 6px 0;
font-family: din-regular, helvetica, sans-serif;
border-top: 1px solid rgba(0, 0, 0, 0.1);
&:hover {
color: #333;
background: $notifications-hover-color;
}
}
}
} }
.controller-notifications { .controller-notifications {
ul.notifications {
list-style: none;
}
.notificationPage, .notificationPage,
.notificationsPage { .notificationsPage {
font-family: 'din-regular', Sans-Serif; font-family: 'din-regular', Sans-Serif;
@ -109,9 +47,89 @@ $unread_notifications_dot_size: 8px;
.emptyInbox { .emptyInbox {
padding-top: 15px; padding-top: 15px;
} }
.notification {
padding: 10px;
position: relative;
&:hover {
background: #F6F6F6;
.notification-read-unread {
display:block;
}
.notification-date {
display: none;
}
}
& > a {
float: left;
width: 85%;
box-sizing: border-box;
padding-right: 10px;
}
.notification-actor {
float: left;
img {
width: 32px;
height: 32px;
border-radius: 16px;
}
}
.notification-body {
margin-left: 50px;
line-height: 20px;
.in-bold {
font-family: 'din-medium', Sans-Serif;
}
.action {
background: #4fb5c0;
color: #FFF;
padding: 2px 6px;
border-radius: 3px;
display: inline-block;
margin: 5px 0;
}
}
.notification-date {
position: absolute;
top: 50%;
right: 10px;
color: #607d8b;
font-size: 13px;
line-height: 13px;
margin-top: -6px;
}
.notification-read-unread {
display: none;
float: left;
width: 15%;
a {
position: absolute;
top: 50%;
margin-top: -10px;
text-align: center;
}
}
&.unread {
background: #EEE;
}
}
} }
.notificationPage { .notificationPage {
.thirty-two-avatar { .thirty-two-avatar {
@ -121,14 +139,14 @@ $unread_notifications_dot_size: 8px;
border-radius: 16px; border-radius: 16px;
vertical-align: middle; vertical-align: middle;
} }
.button { .button {
line-height: 32px; line-height: 32px;
img { img {
margin-top: 8px; margin-top: 8px;
} }
&.decline { &.decline {
background: #DB5D5D; background: #DB5D5D;
&:hover { &:hover {
@ -136,7 +154,7 @@ $unread_notifications_dot_size: 8px;
} }
} }
} }
.notification-body { .notification-body {
p, div { p, div {
margin: 1em auto; margin: 1em auto;
@ -145,93 +163,3 @@ $unread_notifications_dot_size: 8px;
} }
} }
} }
ul.notifications {
list-style: none;
li:nth-last-child(2) {
.notification-body {
border-bottom: none !important;
}
}
}
.notification {
padding: 10px 10px 0 10px;
position: relative;
font-family: 'din-regular', Sans-Serif;
&.unread {
background: #EEE;
}
&:hover {
background: $notifications-hover-color;
.notification-read-unread {
display:block;
}
.notification-date {
display: none;
}
}
& > a {
float: left;
width: 85%;
box-sizing: border-box;
padding-right: 10px;
}
.notification-actor {
float: left;
img {
width: 32px;
height: 32px;
border-radius: 16px;
}
}
.notification-body {
margin-left: 50px;
line-height: 20px;
padding-bottom: 10px;
.in-bold {
font-family: 'din-medium', Sans-Serif;
}
.action {
background: #4fb5c0;
color: #FFF;
padding: 2px 6px;
border-radius: 3px;
display: inline-block;
margin: 5px 0;
}
}
.notification-date {
position: absolute;
top: 50%;
right: 10px;
color: #607d8b;
margin-top: -6px;
}
.notification-read-unread {
display: none;
float: left;
width: 15%;
a, div {
position: absolute;
top: 50%;
margin-top: -10px;
text-align: center;
cursor: pointer;
}
}
}

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module ApplicationCable module ApplicationCable
class Channel < ActionCable::Channel::Base class Channel < ActionCable::Channel::Base
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module ApplicationCable module ApplicationCable
class Connection < ActionCable::Connection::Base class Connection < ActionCable::Connection::Base
identified_by :current_user identified_by :current_user

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MapChannel < ApplicationCable::Channel class MapChannel < ApplicationCable::Channel
# Called when the consumer has successfully # Called when the consumer has successfully
# become a subscriber of this channel. # become a subscriber of this channel.

View file

@ -1,12 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
class AccessController < ApplicationController class AccessController < ApplicationController
before_action :require_user, only: %i[access access_request before_action :require_user, only: [:access, :access_request,
approve_access approve_access_post :approve_access, :approve_access_post,
deny_access deny_access_post request_access] :deny_access, :deny_access_post, :request_access]
before_action :set_map, only: %i[access access_request before_action :set_map, only: [:access, :access_request,
approve_access approve_access_post :approve_access, :approve_access_post,
deny_access deny_access_post request_access] :deny_access, :deny_access_post, :request_access]
after_action :verify_authorized after_action :verify_authorized
# GET maps/:id/request_access # GET maps/:id/request_access

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V1 module V1
class DeprecatedController < ApplicationController class DeprecatedController < ApplicationController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class MappingsController < WithUpdatesController class MappingsController < WithUpdatesController

View file

@ -1,10 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class MapsController < WithUpdatesController class MapsController < WithUpdatesController
def searchable_columns def searchable_columns
%i[name desc] [:name, :desc]
end end
def apply_filters(collection) def apply_filters(collection)

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class MetacodesController < RestfulController class MetacodesController < RestfulController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class RestfulController < ActionController::Base class RestfulController < ActionController::Base
@ -8,7 +7,7 @@ module Api
snorlax_used_rest! snorlax_used_rest!
before_action :load_resource, only: %i[show update destroy] before_action :load_resource, only: [:show, :update, :destroy]
after_action :verify_authorized after_action :verify_authorized
def index def index
@ -92,7 +91,7 @@ module Api
end end
def doorkeeper_user def doorkeeper_user
return if doorkeeper_token.blank? return unless doorkeeper_token.present?
doorkeeper_render_error unless valid_doorkeeper_token? doorkeeper_render_error unless valid_doorkeeper_token?
@doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id) @doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id)
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class SessionsController < ApplicationController class SessionsController < ApplicationController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class StarsController < RestfulController class StarsController < RestfulController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class SynapsesController < WithUpdatesController class SynapsesController < WithUpdatesController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class TokensController < RestfulController class TokensController < RestfulController

View file

@ -1,10 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class TopicsController < WithUpdatesController class TopicsController < WithUpdatesController
def searchable_columns def searchable_columns
%i[name desc link] [:name, :desc, :link]
end end
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class UsersController < RestfulController class UsersController < RestfulController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Api module Api
module V2 module V2
class WithUpdatesController < RestfulController class WithUpdatesController < RestfulController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
include ApplicationHelper include ApplicationHelper
include Pundit include Pundit

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class ExploreController < ApplicationController class ExploreController < ApplicationController
before_action :require_authentication, only: %i[mine shared starred] before_action :require_authentication, only: [:mine, :shared, :starred]
before_action :authorize_explore before_action :authorize_explore
after_action :verify_authorized after_action :verify_authorized
after_action :verify_policy_scoped after_action :verify_policy_scoped

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
# bad code that should be checked over before entering one of the # bad code that should be checked over before entering one of the
# nice files from the right side of this repo # nice files from the right side of this repo
class HacksController < ApplicationController class HacksController < ApplicationController

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MainController < ApplicationController class MainController < ApplicationController
before_action :authorize_main before_action :authorize_main
after_action :verify_authorized after_action :verify_authorized

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class MappingsController < ApplicationController class MappingsController < ApplicationController
before_action :require_user, only: %i[create update destroy] before_action :require_user, only: [:create, :update, :destroy]
after_action :verify_authorized, except: :index after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index after_action :verify_policy_scoped, only: :index

View file

@ -1,10 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class MapsController < ApplicationController class MapsController < ApplicationController
before_action :require_user, only: %i[create update destroy events follow unfollow] before_action :require_user, only: [:create, :update, :destroy, :events, :follow, :unfollow]
before_action :set_map, only: %i[show conversation update destroy before_action :set_map, only: [:show, :conversation, :update, :destroy, :contains, :events, :export, :follow, :unfollow, :unfollow_from_email]
contains events export
follow unfollow unfollow_from_email]
after_action :verify_authorized after_action :verify_authorized
# GET maps/:id # GET maps/:id
@ -26,7 +23,7 @@ class MapsController < ApplicationController
format.ttl { redirect_to action: :export, format: :ttl } format.ttl { redirect_to action: :export, format: :ttl }
end end
end end
# GET maps/:id/conversation # GET maps/:id/conversation
def conversation def conversation
respond_to do |format| respond_to do |format|
@ -143,7 +140,7 @@ class MapsController < ApplicationController
# POST maps/:id/follow # POST maps/:id/follow
def follow def follow
follow = FollowService.follow(@map, current_user, 'followed') follow = FollowService.follow(@map, current_user, 'followed')
respond_to do |format| respond_to do |format|
format.json do format.json do
@ -158,7 +155,7 @@ class MapsController < ApplicationController
# POST maps/:id/unfollow # POST maps/:id/unfollow
def unfollow def unfollow
FollowService.unfollow(@map, current_user) FollowService.unfollow(@map, current_user)
respond_to do |format| respond_to do |format|
format.json do format.json do

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MessagesController < ApplicationController class MessagesController < ApplicationController
before_action :require_user, except: [:show] before_action :require_user, except: [:show]
after_action :verify_authorized after_action :verify_authorized

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MetacodeSetsController < ApplicationController class MetacodeSetsController < ApplicationController
before_action :require_admin before_action :require_admin

View file

@ -1,8 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class MetacodesController < ApplicationController class MetacodesController < ApplicationController
before_action :require_admin, except: %i[index show] before_action :require_admin, except: [:index, :show]
before_action :set_metacode, only: %i[edit update] before_action :set_metacode, only: [:edit, :update]
# GET /metacodes # GET /metacodes
# GET /metacodes.json # GET /metacodes.json

View file

@ -1,23 +1,18 @@
# frozen_string_literal: true # frozen_string_literal: true
class NotificationsController < ApplicationController class NotificationsController < ApplicationController
before_action :set_receipts, only: %i[index show mark_read mark_unread] before_action :set_receipts, only: [:index, :show, :mark_read, :mark_unread]
before_action :set_notification, only: %i[show mark_read mark_unread] before_action :set_notification, only: [:show, :mark_read, :mark_unread]
before_action :set_receipt, only: %i[show mark_read mark_unread] before_action :set_receipt, only: [:show, :mark_read, :mark_unread]
def index def index
@notifications = current_user.mailbox.notifications.page(params[:page]).per(25) @notifications = current_user.mailbox.notifications.page(params[:page]).per(25)
respond_to do |format| respond_to do |format|
format.html format.html
format.json do format.json do
notifications = @notifications.map do |notification| render json: @notifications.map do |notification|
receipt = @receipts.find_by(notification_id: notification.id) receipt = @receipts.find_by(notification_id: notification.id)
NotificationDecorator.decorate(notification, receipt) notification.as_json.merge(is_read: receipt.is_read)
end
if !notifications.empty?
render json: notifications
else
render json: [].to_json
end end
end end
end end
@ -28,18 +23,20 @@ class NotificationsController < ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
case @notification.notification_code case @notification.notification_code
when MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT when MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT
redirect_to map_path(@notification.notified_object.map) redirect_to map_path(@notification.notified_object.map)
when TOPIC_ADDED_TO_MAP when TOPIC_ADDED_TO_MAP
redirect_to map_path(@notification.notified_object.map) redirect_to map_path(@notification.notified_object.map)
when TOPIC_CONNECTED_1 when TOPIC_CONNECTED_1
redirect_to topic_path(@notification.notified_object.topic1) redirect_to topic_path(@notification.notified_object.topic1)
when TOPIC_CONNECTED_2 when TOPIC_CONNECTED_2
redirect_to topic_path(@notification.notified_object.topic2) redirect_to topic_path(@notification.notified_object.topic2)
end end
end end
format.json do format.json do
render json: NotificationDecorator.decorate(@notification, @receipt) render json: @notification.as_json.merge(
is_read: @receipt.is_read
)
end end
end end
end end
@ -49,7 +46,9 @@ class NotificationsController < ApplicationController
respond_to do |format| respond_to do |format|
format.js format.js
format.json do format.json do
render json: NotificationDecorator.decorate(@notification, @receipt) render json: @notification.as_json.merge(
is_read: @receipt.is_read
)
end end
end end
end end
@ -59,7 +58,9 @@ class NotificationsController < ApplicationController
respond_to do |format| respond_to do |format|
format.js format.js
format.json do format.json do
render json: NotificationDecorator.decorate(@notification, @receipt) render json: @notification.as_json.merge(
is_read: @receipt.is_read
)
end end
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class SearchController < ApplicationController class SearchController < ApplicationController
include TopicsHelper include TopicsHelper
include MapsHelper include MapsHelper
@ -8,7 +7,7 @@ class SearchController < ApplicationController
before_action :authorize_search before_action :authorize_search
after_action :verify_authorized after_action :verify_authorized
after_action :verify_policy_scoped, only: %i[maps mappers synapses topics] after_action :verify_policy_scoped, only: [:maps, :mappers, :synapses, :topics]
# get /search/topics?term=SOMETERM # get /search/topics?term=SOMETERM
def topics def topics
@ -141,13 +140,13 @@ class SearchController < ApplicationController
topic1id = params[:topic1id] topic1id = params[:topic1id]
topic2id = params[:topic2id] topic2id = params[:topic2id]
if term.present? if term && !term.empty?
@synapses = policy_scope(Synapse) @synapses = policy_scope(Synapse)
.where('LOWER("desc") like ?', '%' + term.downcase.strip + '%') .where('LOWER("desc") like ?', '%' + term.downcase.strip + '%')
.order('"desc"') .order('"desc"')
@synapses = @synapses.uniq(&:desc) @synapses = @synapses.uniq(&:desc)
elsif topic1id.present? elsif topic1id && !topic1id.empty?
one = policy_scope(Synapse).where(topic1_id: topic1id, topic2_id: topic2id) one = policy_scope(Synapse).where(topic1_id: topic1id, topic2_id: topic2id)
two = policy_scope(Synapse).where(topic2_id: topic1id, topic1_id: topic2id) two = policy_scope(Synapse).where(topic2_id: topic1id, topic1_id: topic2id)
@synapses = one + two @synapses = one + two

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class StarsController < ApplicationController class StarsController < ApplicationController
before_action :require_user before_action :require_user
before_action :set_map before_action :set_map

View file

@ -1,9 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class SynapsesController < ApplicationController class SynapsesController < ApplicationController
include TopicsHelper include TopicsHelper
before_action :require_user, only: %i[create update destroy] before_action :require_user, only: [:create, :update, :destroy]
after_action :verify_authorized, except: :index after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index after_action :verify_policy_scoped, only: :index

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class TokensController < ApplicationController class TokensController < ApplicationController
before_action :require_user, only: [:new] before_action :require_user, only: [:new]

View file

@ -1,12 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
class TopicsController < ApplicationController class TopicsController < ApplicationController
include TopicsHelper include TopicsHelper
before_action :require_user, only: %i[create update destroy follow unfollow] before_action :require_user, only: [:create, :update, :destroy, :follow, :unfollow]
before_action :set_topic, only: %i[show update relative_numbers before_action :set_topic, only: [:show, :update, :relative_numbers,
relatives network destroy :relatives, :network, :destroy,
follow unfollow unfollow_from_email] :follow, :unfollow, :unfollow_from_email]
after_action :verify_authorized, except: :autocomplete_topic after_action :verify_authorized, except: :autocomplete_topic
respond_to :html, :js, :json respond_to :html, :js, :json
@ -14,7 +13,7 @@ class TopicsController < ApplicationController
# GET /topics/autocomplete_topic # GET /topics/autocomplete_topic
def autocomplete_topic def autocomplete_topic
term = params[:term] term = params[:term]
if term.present? if term && !term.empty?
topics = policy_scope(Topic) topics = policy_scope(Topic)
.where('LOWER("name") like ?', term.downcase + '%') .where('LOWER("name") like ?', term.downcase + '%')
.order('"name"') .order('"name"')

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Users module Users
class PasswordsController < Devise::PasswordsController class PasswordsController < Devise::PasswordsController
protected protected

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Users module Users
class RegistrationsController < Devise::RegistrationsController class RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create] before_action :configure_sign_up_params, only: [:create]
@ -30,7 +29,7 @@ module Users
end end
def configure_sign_up_params def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: %i[name joinedwithcode]) devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :joinedwithcode])
end end
def configure_account_update_params def configure_account_update_params

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Users module Users
class SessionsController < Devise::SessionsController class SessionsController < Devise::SessionsController
after_action :store_location, only: [:new] after_action :store_location, only: [:new]

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class UsersController < ApplicationController class UsersController < ApplicationController
before_action :require_user, only: %i[edit update updatemetacodes update_metacode_focus] before_action :require_user, only: [:edit, :update, :updatemetacodes, :update_metacode_focus]
respond_to :html, :json respond_to :html, :json
@ -42,7 +41,7 @@ class UsersController < ApplicationController
correct_pass = @user.valid_password?(params[:current_password]) correct_pass = @user.valid_password?(params[:current_password])
if correct_pass && @user.update_attributes(user_params) if correct_pass && @user.update_attributes(user_params)
update_follow_settings(@user, params[:settings]) update_follow_settings(@user, params[:settings]) if is_tester(@user)
@user.image = nil if params[:remove_image] == '1' @user.image = nil if params[:remove_image] == '1'
@user.save @user.save
sign_in(@user, bypass: true) sign_in(@user, bypass: true)
@ -101,7 +100,7 @@ class UsersController < ApplicationController
@user.settings.metacode_focus = params[:value] @user.settings.metacode_focus = params[:value]
@user.save @user.save
respond_to do |format| respond_to do |format|
format.json { render json: { success: 'success' } } format.json { render json: { success: "success" }}
end end
end end

View file

@ -1,51 +0,0 @@
# frozen_string_literal: true
class NotificationDecorator
class << self
def decorate(notification, receipt)
result = {
id: notification.id,
type: notification.notification_code,
subject: notification.subject,
is_read: receipt.is_read,
created_at: notification.created_at,
actor: notification.sender,
data: {
object: notification.notified_object
}
}
case notification.notification_code
when MAP_ACCESS_APPROVED, MAP_ACCESS_REQUEST, MAP_INVITE_TO_EDIT
map = notification.notified_object&.map
result[:data][:map] = {
id: map&.id,
name: map&.name
}
when TOPIC_ADDED_TO_MAP
topic = notification.notified_object&.eventable
map = notification.notified_object&.map
result[:data][:topic] = {
id: topic&.id,
name: topic&.name
}
result[:data][:map] = {
id: map&.id,
name: map&.name
}
when TOPIC_CONNECTED_1, TOPIC_CONNECTED_2
topic1 = notification.notified_object&.topic1
topic2 = notification.notified_object&.topic2
result[:data][:topic1] = {
id: topic1&.id,
name: topic1&.name
}
result[:data][:topic2] = {
id: topic2&.id,
name: topic2&.name
}
end
result
end
end
end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module ApplicationHelper module ApplicationHelper
def invite_link def invite_link
"#{request.base_url}/join" + (current_user ? "?code=#{current_user.code}" : '') "#{request.base_url}/join" + (current_user ? "?code=#{current_user.code}" : '')

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module ContentHelper module ContentHelper
def resource_name def resource_name
:user :user

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module DeviseHelper module DeviseHelper
def devise_error_messages! def devise_error_messages!
resource.errors.to_a[0] resource.errors.to_a[0]

View file

@ -1,4 +1,3 @@
# frozen_string_literal: true # frozen_string_literal: true
module InMetacodeSetsHelper module InMetacodeSetsHelper
end end

View file

@ -1,4 +1,3 @@
# frozen_string_literal: true # frozen_string_literal: true
module MainHelper module MainHelper
end end

View file

@ -1,5 +1,3 @@
# frozen_string_literal: true
module MapMailerHelper module MapMailerHelper
def access_approved_subject(map) def access_approved_subject(map)
map.name + ' - access approved' map.name + ' - access approved'
@ -7,9 +5,9 @@ module MapMailerHelper
def access_request_subject(map) def access_request_subject(map)
map.name + ' - request to edit' map.name + ' - request to edit'
end end
def invite_to_edit_subject(map) def invite_to_edit_subject(map)
map.name + ' - invited to edit' map.name + ' - invited to edit'
end end
end end

View file

@ -1,4 +1,3 @@
# frozen_string_literal: true # frozen_string_literal: true
module MappingHelper module MappingHelper
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module MapsHelper module MapsHelper
# JSON autocomplete format for typeahead # JSON autocomplete format for typeahead
def autocomplete_map_array_json(maps) def autocomplete_map_array_json(maps)

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module MetacodesHelper module MetacodesHelper
def metacodeset def metacodeset
metacodes = current_user.settings.metacodes metacodes = current_user.settings.metacodes

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module SynapsesHelper module SynapsesHelper
## this one is for building our custom JSON autocomplete format for typeahead ## this one is for building our custom JSON autocomplete format for typeahead
def autocomplete_synapse_generic_json(unique) def autocomplete_synapse_generic_json(unique)

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module TopicMailerHelper module TopicMailerHelper
def added_to_map_subject(topic, map) def added_to_map_subject(topic, map)
topic.name + ' was added to map ' + map.name topic.name + ' was added to map ' + map.name
@ -8,4 +7,4 @@ module TopicMailerHelper
def connected_subject(topic) def connected_subject(topic)
'new synapse to topic ' + topic.name 'new synapse to topic ' + topic.name
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module TopicsHelper module TopicsHelper
## this one is for building our custom JSON autocomplete format for typeahead ## this one is for building our custom JSON autocomplete format for typeahead
def autocomplete_array_json(topics) def autocomplete_array_json(topics)
@ -17,7 +16,7 @@ module TopicsHelper
rtype: is_map ? 'map' : 'topic', rtype: is_map ? 'map' : 'topic',
inmaps: is_map ? [] : t.inmaps(current_user), inmaps: is_map ? [] : t.inmaps(current_user),
inmapsLinks: is_map ? [] : t.inmaps_links(current_user), inmapsLinks: is_map ? [] : t.inmapsLinks(current_user),
type: is_map ? metamap_metacode.name : t.metacode.name, type: is_map ? metamap_metacode.name : t.metacode.name,
typeImageURL: is_map ? metamap_metacode.icon : t.metacode.icon, typeImageURL: is_map ? metamap_metacode.icon : t.metacode.icon,
mapCount: is_map ? 0 : t.maps.count, mapCount: is_map ? 0 : t.maps.count,

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module UsersHelper module UsersHelper
# build custom json autocomplete for typeahead # build custom json autocomplete for typeahead
def autocomplete_user_array_json(users) def autocomplete_user_array_json(users)

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationMailer < ActionMailer::Base class ApplicationMailer < ActionMailer::Base
default from: 'team@metamaps.cc' default from: 'team@metamaps.cc'
layout 'mailer' layout 'mailer'
@ -7,24 +6,24 @@ class ApplicationMailer < ActionMailer::Base
class << self class << self
def mail_for_notification(notification) def mail_for_notification(notification)
case notification.notification_code case notification.notification_code
when MAP_ACCESS_REQUEST when MAP_ACCESS_REQUEST
request = notification.notified_object request = notification.notified_object
MapMailer.access_request(request) MapMailer.access_request(request)
when MAP_ACCESS_APPROVED when MAP_ACCESS_APPROVED
request = notification.notified_object request = notification.notified_object
MapMailer.access_approved(request) MapMailer.access_approved(request)
when MAP_INVITE_TO_EDIT when MAP_INVITE_TO_EDIT
user_map = notification.notified_object user_map = notification.notified_object
MapMailer.invite_to_edit(user_map) MapMailer.invite_to_edit(user_map)
when TOPIC_ADDED_TO_MAP when TOPIC_ADDED_TO_MAP
event = notification.notified_object event = notification.notified_object
TopicMailer.added_to_map(event, notification.recipients[0]) TopicMailer.added_to_map(event, notification.recipients[0])
when TOPIC_CONNECTED_1 when TOPIC_CONNECTED_1
synapse = notification.notified_object synapse = notification.notified_object
TopicMailer.connected(synapse, synapse.topic1, notification.recipients[0]) TopicMailer.connected(synapse, synapse.topic1, notification.recipients[0])
when TOPIC_CONNECTED_2 when TOPIC_CONNECTED_2
synapse = notification.notified_object synapse = notification.notified_object
TopicMailer.connected(synapse, synapse.topic2, notification.recipients[0]) TopicMailer.connected(synapse, synapse.topic2, notification.recipients[0])
end end
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MapActivityMailer < ApplicationMailer class MapActivityMailer < ApplicationMailer
default from: 'team@metamaps.cc' default from: 'team@metamaps.cc'

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MapMailer < ApplicationMailer class MapMailer < ApplicationMailer
include MapMailerHelper include MapMailerHelper
default from: 'team@metamaps.cc' default from: 'team@metamaps.cc'

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class TopicMailer < ApplicationMailer class TopicMailer < ApplicationMailer
include TopicMailerHelper include TopicMailerHelper
default from: 'team@metamaps.cc' default from: 'team@metamaps.cc'

View file

@ -1,10 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class AccessRequest < ApplicationRecord class AccessRequest < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :map belongs_to :map
has_one :user_map has_one :user_map
after_create :after_created_async after_create :after_created_async
def approve def approve
@ -28,9 +27,9 @@ class AccessRequest < ApplicationRecord
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true) Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
end end
end end
protected protected
def after_created_async def after_created_async
NotificationService.access_request(self) NotificationService.access_request(self)
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true self.abstract_class = true
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class Attachment < ApplicationRecord class Attachment < ApplicationRecord
belongs_to :attachable, polymorphic: true belongs_to :attachable, polymorphic: true

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Attachable module Attachable
extend ActiveSupport::Concern extend ActiveSupport::Concern

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Routing module Routing
extend ActiveSupport::Concern extend ActiveSupport::Concern
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers

View file

@ -1,17 +1,16 @@
# frozen_string_literal: true # frozen_string_literal: true
class Event < ApplicationRecord class Event < ApplicationRecord
KINDS = %w[user_present_on_map user_not_present_on_map KINDS = %w(user_present_on_map user_not_present_on_map
conversation_started_on_map conversation_started_on_map
topic_added_to_map topic_moved_on_map topic_removed_from_map topic_added_to_map topic_moved_on_map topic_removed_from_map
synapse_added_to_map synapse_removed_from_map synapse_added_to_map synapse_removed_from_map
topic_updated synapse_updated].freeze topic_updated synapse_updated).freeze
belongs_to :eventable, polymorphic: true belongs_to :eventable, polymorphic: true
belongs_to :map belongs_to :map
belongs_to :user belongs_to :user
scope :chronologically, (-> { order('created_at asc') }) scope :chronologically, -> { order('created_at asc') }
after_create :notify_webhooks!, if: :map after_create :notify_webhooks!, if: :map

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class ConversationStartedOnMap < Event class ConversationStartedOnMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class SynapseAddedToMap < Event class SynapseAddedToMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class SynapseRemovedFromMap < Event class SynapseRemovedFromMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class SynapseUpdated < Event class SynapseUpdated < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class TopicAddedToMap < Event class TopicAddedToMap < Event
after_create :notify_users! after_create :notify_users!
@ -11,7 +10,7 @@ module Events
user: user, user: user,
meta: meta) meta: meta)
end end
def notify_users! def notify_users!
# in the future, notify followers of both the topic, and the map # in the future, notify followers of both the topic, and the map
NotificationService.notify_followers(eventable, TOPIC_ADDED_TO_MAP, self) NotificationService.notify_followers(eventable, TOPIC_ADDED_TO_MAP, self)

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class TopicMovedOnMap < Event class TopicMovedOnMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class TopicRemovedFromMap < Event class TopicRemovedFromMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,8 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class TopicUpdated < Event class TopicUpdated < Event
# after_create :notify_users! #after_create :notify_users!
def self.publish!(topic, user, meta) def self.publish!(topic, user, meta)
create!(kind: 'topic_updated', create!(kind: 'topic_updated',
@ -10,7 +9,7 @@ module Events
user: user, user: user,
meta: meta) meta: meta)
end end
def notify_users! def notify_users!
NotificationService.notify_followers(eventable, 'topic_updated', self) NotificationService.notify_followers(eventable, 'topic_updated', self)
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class UserNotPresentOnMap < Event class UserNotPresentOnMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events module Events
class UserPresentOnMap < Event class UserPresentOnMap < Event
# after_create :notify_users! # after_create :notify_users!

View file

@ -1,21 +1,23 @@
# frozen_string_literal: true # frozen_string_literal: true
class Follow < ApplicationRecord class Follow < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :followed, polymorphic: true belongs_to :followed, polymorphic: true
has_one :follow_reason, dependent: :destroy has_one :follow_reason, dependent: :destroy
validates :user, presence: true validates :user, presence: true
validates :followed, presence: true validates :followed, presence: true
validates :user, uniqueness: { scope: :followed, message: 'This entity is already followed by this user' } validates :user, uniqueness: { scope: :followed, message: 'This entity is already followed by this user' }
after_create :add_subsetting after_create :add_subsetting
scope :active, (-> { where(muted: false) }) scope :active, -> {
where(muted: false)
}
private private
def add_subsetting def add_subsetting
FollowReason.create!(follow: self) follow_reason = FollowReason.create!(follow: self)
end end
end end

View file

@ -1,13 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
class FollowReason < ApplicationRecord class FollowReason < ApplicationRecord
REASONS = %w[created commented contributed followed shared_on starred].freeze REASONS = %w(created commented contributed followed shared_on starred).freeze
belongs_to :follow belongs_to :follow
validates :follow, presence: true validates :follow, presence: true
def has_reason def has_reason
created || commented || contributed || followed || shared_on || starred created || commented || contributed || followed || shared_on || starred
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class InMetacodeSet < ApplicationRecord class InMetacodeSet < ApplicationRecord
belongs_to :metacode, class_name: 'Metacode', foreign_key: 'metacode_id' belongs_to :metacode, class_name: 'Metacode', foreign_key: 'metacode_id'
belongs_to :metacode_set, class_name: 'MetacodeSet', foreign_key: 'metacode_set_id' belongs_to :metacode_set, class_name: 'MetacodeSet', foreign_key: 'metacode_set_id'

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Map < ApplicationRecord class Map < ApplicationRecord
ATTRS_TO_WATCH = %w[name desc permission].freeze ATTRS_TO_WATCH = %w(name desc permission).freeze
belongs_to :user belongs_to :user
belongs_to :source, class_name: :Map belongs_to :source, class_name: :Map
@ -16,7 +15,7 @@ class Map < ApplicationRecord
has_many :messages, as: :resource, dependent: :destroy has_many :messages, as: :resource, dependent: :destroy
has_many :stars, dependent: :destroy has_many :stars, dependent: :destroy
has_many :follows, as: :followed, dependent: :destroy has_many :follows, as: :followed, dependent: :destroy
has_many :followers, through: :follows, source: :user has_many :followers, :through => :follows, source: :user
has_many :access_requests, dependent: :destroy has_many :access_requests, dependent: :destroy
has_many :user_maps, dependent: :destroy has_many :user_maps, dependent: :destroy
@ -90,10 +89,10 @@ class Map < ApplicationRecord
def as_json(_options = {}) def as_json(_options = {})
json = super( json = super(
methods: %i[user_name user_image star_count topic_count synapse_count methods: [:user_name, :user_image, :star_count, :topic_count, :synapse_count,
contributor_count collaborator_ids screenshot_url], :contributor_count, :collaborator_ids, :screenshot_url],
except: %i[screenshot_content_type screenshot_file_size screenshot_file_name except: [:screenshot_content_type, :screenshot_file_size, :screenshot_file_name,
screenshot_updated_at] :screenshot_updated_at]
) )
json[:created_at_clean] = created_at_str json[:created_at_clean] = created_at_str
json[:updated_at_clean] = updated_at_str json[:updated_at_clean] = updated_at_str
@ -134,16 +133,16 @@ class Map < ApplicationRecord
end end
removed.compact removed.compact
end end
def update_deferring_topics_and_synapses def update_deferring_topics_and_synapses
Topic.where(defer_to_map_id: id).update(permission: permission) Topic.where(defer_to_map_id: id).update(permission: permission)
Synapse.where(defer_to_map_id: id).update(permission: permission) Synapse.where(defer_to_map_id: id).update(permission: permission)
end end
protected protected
def after_created def after_created
FollowService.follow(self, user, 'created') FollowService.follow(self, self.user, 'created')
# notify users following the map creator # notify users following the map creator
end end
@ -151,12 +150,13 @@ class Map < ApplicationRecord
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated' ActionCable.server.broadcast 'map_' + id.to_s, type: 'mapUpdated'
end end
def after_updated_async def after_updated_async
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
FollowService.follow(self, updated_by, 'contributed') FollowService.follow(self, updated_by, 'contributed')
# NotificationService.notify_followers(self, 'map_updated', changed_attributes) # NotificationService.notify_followers(self, 'map_updated', changed_attributes)
# or better yet publish an event # or better yet publish an event
end
end end
handle_asynchronously :after_updated_async handle_asynchronously :after_updated_async

View file

@ -1,8 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Mapping < ApplicationRecord class Mapping < ApplicationRecord
scope :topicmapping, (-> { where(mappable_type: :Topic) }) scope :topicmapping, -> { where(mappable_type: :Topic) }
scope :synapsemapping, (-> { where(mappable_type: :Synapse) }) scope :synapsemapping, -> { where(mappable_type: :Synapse) }
belongs_to :mappable, polymorphic: true belongs_to :mappable, polymorphic: true
belongs_to :map, class_name: 'Map', foreign_key: 'map_id', touch: true belongs_to :map, class_name: 'Map', foreign_key: 'map_id', touch: true
@ -25,7 +24,7 @@ class Mapping < ApplicationRecord
end end
def as_json(_options = {}) def as_json(_options = {})
super(methods: %i[user_name user_image]) super(methods: [:user_name, :user_image])
end end
def after_created def after_created
@ -53,17 +52,17 @@ class Mapping < ApplicationRecord
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def after_updated def after_updated
return unless (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?) if (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
meta = { 'x': xloc, 'y': yloc, 'mapping_id': id } meta = { 'x': xloc, 'y': yloc, 'mapping_id': id }
Events::TopicMovedOnMap.publish!(mappable, map, updated_by, meta) Events::TopicMovedOnMap.publish!(mappable, map, updated_by, meta)
ActionCable.server.broadcast('map_' + map.id.to_s, type: 'topicMoved', ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicMoved', id: mappable.id, mapping_id: id, x: xloc, y: yloc
id: mappable.id, mapping_id: id, end
x: xloc, y: yloc)
end end
def after_updated_async def after_updated_async
return unless (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?) if (mappable_type == 'Topic') && (xloc_changed? || yloc_changed?)
FollowService.follow(map, updated_by, 'contributed') FollowService.follow(map, updated_by, 'contributed')
end
end end
handle_asynchronously :after_updated_async handle_asynchronously :after_updated_async

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class Message < ApplicationRecord class Message < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :resource, polymorphic: true belongs_to :resource, polymorphic: true
@ -7,14 +6,15 @@ class Message < ApplicationRecord
delegate :name, to: :user, prefix: true delegate :name, to: :user, prefix: true
after_create :after_created after_create :after_created
# after_create :after_created_async #after_create :after_created_async
def user_image def user_image
user.image.url user.image.url
end end
def as_json(_options = {}) def as_json(_options = {})
json = super(methods: %i[user_name user_image]) json = super(methods: [:user_name, :user_image])
json json
end end

View file

@ -1,16 +1,17 @@
# frozen_string_literal: true # frozen_string_literal: true
class Metacode < ApplicationRecord class Metacode < ApplicationRecord
has_many :in_metacode_sets has_many :in_metacode_sets
has_many :metacode_sets, through: :in_metacode_sets has_many :metacode_sets, through: :in_metacode_sets
has_many :topics has_many :topics
# This method associates the attribute ":aws_icon" with a file attachment # This method associates the attribute ":aws_icon" with a file attachment
has_attached_file :aws_icon, styles: { ninetysix: ['96x96#', :png] }, has_attached_file :aws_icon, styles: {
ninetysix: ['96x96#', :png]
},
default_url: 'https://s3.amazonaws.com/metamaps-assets/metacodes/generics/96px/gen_wildcard.png' default_url: 'https://s3.amazonaws.com/metamaps-assets/metacodes/generics/96px/gen_wildcard.png'
# Validate the attached icon is image/jpg, image/png, etc # Validate the attached icon is image/jpg, image/png, etc
validates_attachment_content_type :aws_icon, content_type: %r{\Aimage/.*\Z} validates_attachment_content_type :aws_icon, content_type: /\Aimage\/.*\Z/
validate :aws_xor_manual_icon validate :aws_xor_manual_icon
validate :manual_icon_https validate :manual_icon_https
@ -29,13 +30,15 @@ class Metacode < ApplicationRecord
def as_json(options = {}) def as_json(options = {})
default = super(options) default = super(options)
default[:icon] = icon default[:icon] = icon
default.except( default.except('aws_icon_file_name', 'aws_icon_content_type', 'aws_icon_file_size', 'aws_icon_updated_at', 'manual_icon')
'aws_icon_file_name', 'aws_icon_content_type', 'aws_icon_file_size', 'aws_icon_updated_at',
'manual_icon'
)
end end
def in_metacode_set(metacode_set) def hasSelected(user)
return true if user.settings.metacodes.include? id.to_s
false
end
def inMetacodeSet(metacode_set)
return true if metacode_sets.include? metacode_set return true if metacode_sets.include? metacode_set
false false
end end
@ -52,9 +55,10 @@ class Metacode < ApplicationRecord
end end
def manual_icon_https def manual_icon_https
return if manual_icon.blank? if manual_icon.present?
unless manual_icon.starts_with? 'https' unless manual_icon.starts_with? 'https'
errors.add(:base, 'Manual icon must begin with https') errors.add(:base, 'Manual icon must begin with https')
end
end end
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class MetacodeSet < ApplicationRecord class MetacodeSet < ApplicationRecord
belongs_to :user belongs_to :user
has_many :in_metacode_sets has_many :in_metacode_sets

View file

@ -1,18 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
class PermittedParams < Struct.new(:params)
class PermittedParams %w(map synapse topic mapping token).each do |kind|
%w[map synapse topic mapping token].each do |kind|
define_method(kind) do define_method(kind) do
permitted_attributes = send("#{kind}_attributes") permitted_attributes = send("#{kind}_attributes")
@params.require(kind).permit(*permitted_attributes) params.require(kind).permit(*permitted_attributes)
end end
alias_method :"api_#{kind}", kind.to_sym alias_method :"api_#{kind}", kind.to_sym
end end
def initialize(params)
@params = params
end
alias read_attribute_for_serialization send alias read_attribute_for_serialization send
def token_attributes def token_attributes
@ -20,18 +15,18 @@ class PermittedParams
end end
def map_attributes def map_attributes
%i[name desc permission arranged] [:name, :desc, :permission, :arranged]
end end
def synapse_attributes def synapse_attributes
%i[desc category weight permission topic1_id topic2_id] [:desc, :category, :weight, :permission, :topic1_id, :topic2_id]
end end
def topic_attributes def topic_attributes
%i[name desc link permission metacode_id] [:name, :desc, :link, :permission, :metacode_id]
end end
def mapping_attributes def mapping_attributes
%i[xloc yloc map_id mappable_type mappable_id] [:xloc, :yloc, :map_id, :mappable_type, :mappable_id]
end end
end end

View file

@ -1,21 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
class Star < ActiveRecord::Base
class Star < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :map belongs_to :map
validates :map, uniqueness: { scope: :user, message: 'You have already starred this map' } validates :map, uniqueness: { scope: :user, message: 'You have already starred this map' }
# after_create :after_created_async #after_create :after_created_async
# before_destroy :before_destroyed #before_destroy :before_destroyed
protected protected
def after_created_async def after_created_async
FollowService.follow(map, user, 'starred') FollowService.follow(map, user, 'starred')
NotificationService.notify_followers(map, 'map_starred', self, 'created') NotificationService.notify_followers(map, 'map_starred', self, 'created')
end end
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def before_destroyed def before_destroyed
FollowService.remove_reason(map, user, 'starred') FollowService.remove_reason(map, user, 'starred')
end end

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Synapse < ApplicationRecord class Synapse < ApplicationRecord
ATTRS_TO_WATCH = %w[desc category permission defer_to_map_id].freeze ATTRS_TO_WATCH = %w(desc category permission defer_to_map_id).freeze
belongs_to :user belongs_to :user
belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id' belongs_to :defer_to_map, class_name: 'Map', foreign_key: 'defer_to_map_id'
@ -22,9 +21,9 @@ class Synapse < ApplicationRecord
validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true } validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true }
scope :for_topic, (lambda do |topic_id = nil| scope :for_topic, ->(topic_id = nil) {
where(topic1_id: topic_id).or(where(topic2_id: topic_id)) where(topic1_id: topic_id).or(where(topic2_id: topic_id))
end) }
before_create :set_perm_by_defer before_create :set_perm_by_defer
after_create :after_created_async after_create :after_created_async
@ -39,7 +38,7 @@ class Synapse < ApplicationRecord
def collaborator_ids def collaborator_ids
if defer_to_map if defer_to_map
defer_to_map.editors.reject { |mapper| mapper == user }.map(&:id) defer_to_map.editors.select { |mapper| mapper != user }.map(&:id)
else else
[] []
end end
@ -55,7 +54,7 @@ class Synapse < ApplicationRecord
end end
def as_json(_options = {}) def as_json(_options = {})
super(methods: %i[user_name user_image collaborator_ids]) super(methods: [:user_name, :user_image, :collaborator_ids])
end end
def as_rdf def as_rdf
@ -73,7 +72,7 @@ class Synapse < ApplicationRecord
protected protected
def set_perm_by_defer def set_perm_by_defer
defer_to_map&.permission permission = defer_to_map.permission if defer_to_map
end end
def after_created_async def after_created_async
@ -83,21 +82,21 @@ class Synapse < ApplicationRecord
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def after_updated def after_updated
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) } old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) } meta = new.merge(old) # we are prioritizing the old values, keeping them
meta = new.merge(old) # we are prioritizing the old values, keeping them meta['changed'] = changed_attributes.keys.select { |k| ATTRS_TO_WATCH.include?(k) }
meta['changed'] = changed_attributes.keys.select { |k| ATTRS_TO_WATCH.include?(k) } Events::SynapseUpdated.publish!(self, updated_by, meta)
Events::SynapseUpdated.publish!(self, updated_by, meta) maps.each do |map|
maps.each do |map| ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'synapseUpdated', id: id
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'synapseUpdated', id: id end
end end
end end
def before_destroyed def before_destroyed
# hard to know how to do this yet, because the synapse actually gets destroyed # hard to know how to do this yet, because the synapse actually gets destroyed
# NotificationService.notify_followers(topic1, 'topic_disconnected', self) #NotificationService.notify_followers(topic1, 'topic_disconnected', self)
# NotificationService.notify_followers(topic2, 'topic_disconnected', self) #NotificationService.notify_followers(topic2, 'topic_disconnected', self)
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class Token < ApplicationRecord class Token < ApplicationRecord
belongs_to :user belongs_to :user

View file

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
class Topic < ApplicationRecord class Topic < ApplicationRecord
ATTRS_TO_WATCH = %w[name desc link metacode_id permission defer_to_map_id].freeze ATTRS_TO_WATCH = %w(name desc link metacode_id permission defer_to_map_id).freeze
include TopicsHelper include TopicsHelper
include Attachable include Attachable
@ -17,7 +16,7 @@ class Topic < ApplicationRecord
has_many :mappings, as: :mappable, dependent: :destroy has_many :mappings, as: :mappable, dependent: :destroy
has_many :maps, through: :mappings has_many :maps, through: :mappings
has_many :follows, as: :followed, dependent: :destroy has_many :follows, as: :followed, dependent: :destroy
has_many :followers, through: :follows, source: :user has_many :followers, :through => :follows, source: :user
belongs_to :metacode belongs_to :metacode
@ -26,7 +25,7 @@ class Topic < ApplicationRecord
after_create :after_created_async after_create :after_created_async
after_update :after_updated after_update :after_updated
after_update :after_updated_async after_update :after_updated_async
# before_destroy :before_destroyed #before_destroy :before_destroyed
validates :permission, presence: true validates :permission, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) } validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
@ -39,13 +38,13 @@ class Topic < ApplicationRecord
topics1.or(topics2) topics1.or(topics2)
end end
scope :relatives, (lambda do |topic_id = nil, user = nil| scope :relatives, ->(topic_id = nil, user = nil) {
# should only see topics through *visible* synapses # should only see topics through *visible* synapses
# e.g. Topic A (commons) -> synapse (private) -> Topic B (commons) must be filtered out # e.g. Topic A (commons) -> synapse (private) -> Topic B (commons) must be filtered out
topic_ids = Pundit.policy_scope(user, Synapse.where(topic1_id: topic_id)).pluck(:topic2_id) topic_ids = Pundit.policy_scope(user, Synapse.where(topic1_id: topic_id)).pluck(:topic2_id)
topic_ids += Pundit.policy_scope(user, Synapse.where(topic2_id: topic_id)).pluck(:topic1_id) topic_ids += Pundit.policy_scope(user, Synapse.where(topic2_id: topic_id)).pluck(:topic1_id)
where(id: topic_ids.uniq) where(id: topic_ids.uniq)
end) }
delegate :name, to: :user, prefix: true delegate :name, to: :user, prefix: true
@ -65,13 +64,13 @@ class Topic < ApplicationRecord
Pundit.policy_scope(user, maps).map(&:name) Pundit.policy_scope(user, maps).map(&:name)
end end
def inmaps_links(user) def inmapsLinks(user)
Pundit.policy_scope(user, maps).map(&:id) Pundit.policy_scope(user, maps).map(&:id)
end end
def as_json(options = {}) def as_json(options = {})
super(methods: %i[user_name user_image collaborator_ids]) super(methods: [:user_name, :user_image, :collaborator_ids])
.merge(inmaps: inmaps(options[:user]), inmapsLinks: inmaps_links(options[:user]), .merge(inmaps: inmaps(options[:user]), inmapsLinks: inmapsLinks(options[:user]),
map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user])) map_count: map_count(options[:user]), synapse_count: synapse_count(options[:user]))
end end
@ -90,7 +89,7 @@ class Topic < ApplicationRecord
def collaborator_ids def collaborator_ids
if defer_to_map if defer_to_map
defer_to_map.editors.reject { |mapper| mapper == user }.map(&:id) defer_to_map.editors.select { |mapper| mapper != user }.map(&:id)
else else
[] []
end end
@ -127,9 +126,14 @@ class Topic < ApplicationRecord
end end
end end
end end
return output if output_format == 'array' if output_format == 'array'
return output.join('; ') if output_format == 'text' return output
raise 'invalid argument to synapses_csv' elsif output_format == 'text'
return output.join('; ')
else
raise 'invalid argument to synapses_csv'
end
output
end end
def topic_autocomplete_method def topic_autocomplete_method
@ -139,7 +143,7 @@ class Topic < ApplicationRecord
protected protected
def set_perm_by_defer def set_perm_by_defer
self.permission = defer_to_map.permission if defer_to_map permission = defer_to_map.permission if defer_to_map
end end
def create_metamap? def create_metamap?
@ -150,35 +154,35 @@ class Topic < ApplicationRecord
self.link = Rails.application.routes.url_helpers self.link = Rails.application.routes.url_helpers
.map_url(host: ENV['MAILER_DEFAULT_URL'], id: @map.id) .map_url(host: ENV['MAILER_DEFAULT_URL'], id: @map.id)
end end
def after_created_async def after_created_async
FollowService.follow(self, user, 'created') FollowService.follow(self, self.user, 'created')
# notify users following the topic creator # notify users following the topic creator
end end
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def after_updated def after_updated
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
new = attributes.select { |k| ATTRS_TO_WATCH.include?(k) } old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) }
old = changed_attributes.select { |k| ATTRS_TO_WATCH.include?(k) } meta = new.merge(old) # we are prioritizing the old values, keeping them
meta = new.merge(old) # we are prioritizing the old values, keeping them meta['changed'] = changed_attributes.keys.select { |k| ATTRS_TO_WATCH.include?(k) }
meta['changed'] = changed_attributes.keys.select { |k| ATTRS_TO_WATCH.include?(k) } Events::TopicUpdated.publish!(self, updated_by, meta)
Events::TopicUpdated.publish!(self, updated_by, meta) maps.each do |map|
maps.each do |map| ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicUpdated', id: id
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicUpdated', id: id end
end end
end end
def after_updated_async def after_updated_async
return unless ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) } if ATTRS_TO_WATCH.any? { |k| changed_attributes.key?(k) }
FollowService.follow(self, updated_by, 'contributed')
FollowService.follow(self, updated_by, 'contributed') end
end end
handle_asynchronously :after_updated_async handle_asynchronously :after_updated_async
def before_destroyed def before_destroyed
# hard to know how to do this yet, because the topic actually gets destroyed # hard to know how to do this yet, because the topic actually gets destroyed
# NotificationService.notify_followers(self, 'topic_deleted', ?) #NotificationService.notify_followers(self, 'topic_deleted', ?)
end end
end end

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'open-uri' require 'open-uri'
class User < ApplicationRecord class User < ApplicationRecord
@ -52,24 +51,26 @@ class User < ApplicationRecord
validates_attachment_content_type :image, content_type: %r{\Aimage/.*\Z} validates_attachment_content_type :image, content_type: %r{\Aimage/.*\Z}
# override default as_json # override default as_json
def as_json(options = {}) def as_json(_options = {})
json = { id: id, json = { id: id,
name: name, name: name,
image: image.url(:sixtyfour), image: image.url(:sixtyfour),
admin: admin } admin: admin }
if options[:follows] if (_options[:follows])
json['follows'] = { json['follows'] = {
topics: following.active.where(followed_type: 'Topic').to_a.map(&:followed_id), topics: following.active.where(followed_type: 'Topic').to_a.map(&:followed_id),
maps: following.active.where(followed_type: 'Map').to_a.map(&:followed_id) maps: following.active.where(followed_type: 'Map').to_a.map(&:followed_id)
} }
end end
if options[:follow_settings] if (_options[:follow_settings])
json['follow_topic_on_created'] = settings.follow_topic_on_created == '1' json['follow_topic_on_created'] = settings.follow_topic_on_created == "1"
json['follow_topic_on_contributed'] = settings.follow_topic_on_contributed == '1' json['follow_topic_on_contributed'] = settings.follow_topic_on_contributed == "1"
json['follow_map_on_created'] = settings.follow_map_on_created == '1' json['follow_map_on_created'] = settings.follow_map_on_created == "1"
json['follow_map_on_contributed'] = settings.follow_map_on_contributed == '1' json['follow_map_on_contributed'] = settings.follow_map_on_contributed == "1"
end
if (_options[:email])
json['email'] = email
end end
json['email'] = email if options[:email]
json json
end end
@ -106,14 +107,10 @@ class User < ApplicationRecord
end end
def most_used_metacodes def most_used_metacodes
metacode_counts = topics.to_a.each_with_object(Hash.new(0)) do |topic, list_so_far| topics.to_a.each_with_object(Hash.new(0)) do |topic, memo|
list_so_far[topic.metacode_id] += 1 memo[topic.metacode_id] += 1
list_so_far memo
end end.to_a.sort { |a, b| b[1] <=> a[1] }.map { |i| i[0] }.slice(0, 5)
id_count_pairs = metacode_counts.to_a
id_count_pairs.sort! { |a, b| b[1] <=> a[1] }
metacode_ids = id_count_pairs.map { |i| i[0] }
metacode_ids.slice(0, 5)
end end
# generate a random 8 letter/digit code that they can use to invite people # generate a random 8 letter/digit code that they can use to invite people
@ -136,20 +133,20 @@ class User < ApplicationRecord
end end
def has_map_open(map) def has_map_open(map)
latest_event = Event.where(map: map, user: self) latestEvent = Event.where(map: map, user: self)
.where(kind: %w[user_present_on_map user_not_present_on_map]) .where(kind: ['user_present_on_map', 'user_not_present_on_map'])
.order(:created_at) .order(:created_at)
.last .last
latest_event && latest_event.kind == 'user_present_on_map' latestEvent && latestEvent.kind == 'user_present_on_map'
end end
def has_map_with_synapse_open(synapse) def has_map_with_synapse_open(synapse)
synapse.maps.any? { |map| has_map_open(map) } synapse.maps.any?{|map| has_map_open(map)}
end end
def settings def settings
self[:settings] = UserPreference.new if self[:settings].nil? self[:settings] = UserPreference.new if self[:settings].nil?
unless self[:settings].respond_to?(:follow_topic_on_created) if not self[:settings].respond_to?(:follow_topic_on_created)
self[:settings].initialize_follow_settings self[:settings].initialize_follow_settings
end end
self[:settings] self[:settings]

View file

@ -1,10 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class UserMap < ApplicationRecord class UserMap < ApplicationRecord
belongs_to :map belongs_to :map
belongs_to :user belongs_to :user
belongs_to :access_request belongs_to :access_request
after_create :after_created_async after_create :after_created_async
before_destroy :before_destroyed before_destroy :before_destroyed
@ -13,20 +12,20 @@ class UserMap < ApplicationRecord
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true) Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
end end
end end
protected protected
def after_created_async def after_created_async
FollowService.follow(map, user, 'shared_on') FollowService.follow(map, user, 'shared_on')
if access_request if access_request
NotificationService.access_approved(access_request) NotificationService.access_approved(self.access_request)
else else
NotificationService.invite_to_edit(self) NotificationService.invite_to_edit(self)
end end
# NotificationService.notify_followers(map, 'map_collaborator_added', self, 'shared_on') # NotificationService.notify_followers(map, 'map_collaborator_added', self, 'shared_on')
end end
handle_asynchronously :after_created_async handle_asynchronously :after_created_async
def before_destroyed def before_destroyed
FollowService.remove_reason(map, user, 'shared_on') FollowService.remove_reason(map, user, 'shared_on')
end end

View file

@ -1,34 +1,29 @@
# frozen_string_literal: true # frozen_string_literal: true
class UserPreference class UserPreference
attr_accessor :metacodes, :metacode_focus, :follow_topic_on_created, :follow_topic_on_contributed, attr_accessor :metacodes, :metacode_focus, :follow_topic_on_created, :follow_topic_on_contributed,
:follow_map_on_created, :follow_map_on_contributed :follow_map_on_created, :follow_map_on_contributed
def initialize def initialize
@metacodes = init_metacodes.compact array = []
@metacode_focus = @metacodes[0] %w(Action Aim Idea Question Note Wildcard Subject).each do |m|
initialize_follow_settings
end
private
def init_metacodes
%w[Action Aim Idea Question Note Wildcard Subject].map do |m|
begin begin
metacode = Metacode.find_by(name: m) metacode = Metacode.find_by(name: m)
metacode.id.to_s if metacode array.push(metacode.id.to_s) if metacode
rescue ActiveRecord::StatementInvalid rescue ActiveRecord::StatementInvalid
if m == 'Action' if m == 'Action'
Rails.logger.warn('TODO: remove this travis workaround in user_preference.rb') Rails.logger.warn('TODO: remove this travis workaround in user_preference.rb')
end end
end end
end.compact end
@metacodes = array
@metacode_focus = array[0]
initialize_follow_settings
end end
def initialize_follow_settings def initialize_follow_settings
@follow_topic_on_created = false @follow_topic_on_created = false
@follow_topic_on_contributed = false @follow_topic_on_contributed = false
@follow_map_on_created = true @follow_map_on_created = false
@follow_map_on_contributed = false @follow_map_on_contributed = false
end end
end end

View file

@ -1,11 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class Webhook < ApplicationRecord class Webhook < ApplicationRecord
belongs_to :hookable, polymorphic: true belongs_to :hookable, polymorphic: true
validates :uri, presence: true validates :uri, presence: true
validates :hookable, presence: true validates :hookable, presence: true
validates :kind, inclusion: { in: %w[slack] } validates :kind, inclusion: { in: %w(slack) }
validates :event_types, length: { minimum: 1 } validates :event_types, length: { minimum: 1 }
def headers def headers

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
Webhooks::Slack::Base = Struct.new(:webhook, :event) do Webhooks::Slack::Base = Struct.new(:webhook, :event) do
include Routing include Routing

View file

@ -1,5 +1,4 @@
# frozen_string_literal: true # frozen_string_literal: true
class Webhooks::Slack::ConversationStartedOnMap < Webhooks::Slack::Base class Webhooks::Slack::ConversationStartedOnMap < Webhooks::Slack::Base
def text def text
"There is a live conversation starting on map *#{event.map.name}*. #{view_map_on_metamaps('Join in!')}" "There is a live conversation starting on map *#{event.map.name}*. #{view_map_on_metamaps('Join in!')}"

View file

@ -1,10 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Webhooks::Slack::SynapseAddedToMap < Webhooks::Slack::Base class Webhooks::Slack::SynapseAddedToMap < Webhooks::Slack::Base
def text def text
connector = eventable.desc.empty? ? '->' : eventable.desc connector = eventable.desc.empty? ? '->' : eventable.desc
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\"" \ "\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\" was added as a connection by *#{event.user.name}* to the map *#{view_map_on_metamaps}*"
" was added as a connection by *#{event.user.name}*" \
" to the map *#{view_map_on_metamaps}*"
end end
end end

View file

@ -1,13 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class Webhooks::Slack::SynapseRemovedFromMap < Webhooks::Slack::Base class Webhooks::Slack::SynapseRemovedFromMap < Webhooks::Slack::Base
def text def text
connector = eventable.desc.empty? ? '->' : eventable.desc connector = eventable.desc.empty? ? '->' : eventable.desc
# TODO: express correct directionality of arrows when desc is empty # TODO: express correct directionality of arrows when desc is empty
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\" was removed by *#{event.user.name}* as a connection from the map *#{view_map_on_metamaps}*"
"\"*#{eventable.topic1.name}* #{connector} *#{eventable.topic2.name}*\"" \
" was removed by *#{event.user.name}* as a connection" \
" from the map *#{view_map_on_metamaps}*"
end end
end end

Some files were not shown because too many files have changed in this diff Show more