Initial notification centre using mailboxer
This commit is contained in:
parent
1ba339b3be
commit
85408a14d3
53 changed files with 778 additions and 109 deletions
|
@ -20,6 +20,8 @@ engines:
|
|||
enabled: true
|
||||
rubocop:
|
||||
enabled: true
|
||||
exclude_fingerprints:
|
||||
- 74f18007b920e8d81148d2f6a2756534
|
||||
ratings:
|
||||
paths:
|
||||
- 'Gemfile.lock'
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -17,6 +17,7 @@ gem 'exception_notification'
|
|||
gem 'httparty'
|
||||
gem 'json'
|
||||
gem 'kaminari'
|
||||
gem 'mailboxer'
|
||||
gem 'paperclip'
|
||||
gem 'pg'
|
||||
gem 'pundit'
|
||||
|
|
10
Gemfile.lock
10
Gemfile.lock
|
@ -65,6 +65,12 @@ GEM
|
|||
brakeman (3.4.0)
|
||||
builder (3.2.2)
|
||||
byebug (9.0.5)
|
||||
carrierwave (0.11.2)
|
||||
activemodel (>= 3.2.0)
|
||||
activesupport (>= 3.2.0)
|
||||
json (>= 1.7)
|
||||
mime-types (>= 1.16)
|
||||
mimemagic (>= 0.3.0)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cocaine (0.5.8)
|
||||
|
@ -125,6 +131,9 @@ GEM
|
|||
nokogiri (>= 1.5.9)
|
||||
mail (2.6.4)
|
||||
mime-types (>= 1.16, < 4)
|
||||
mailboxer (0.14.0)
|
||||
carrierwave (>= 0.5.8)
|
||||
rails (>= 4.2.0)
|
||||
method_source (0.8.2)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
|
@ -284,6 +293,7 @@ DEPENDENCIES
|
|||
json
|
||||
json-schema
|
||||
kaminari
|
||||
mailboxer
|
||||
paperclip
|
||||
pg
|
||||
pry-byebug
|
||||
|
|
BIN
app/assets/images/.DS_Store
vendored
BIN
app/assets/images/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
app/assets/images/user_sprite.png
Executable file → Normal file
BIN
app/assets/images/user_sprite.png
Executable file → Normal file
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -826,7 +826,7 @@ label {
|
|||
position:absolute;
|
||||
pointer-events:none;
|
||||
background-repeat:no-repeat;
|
||||
background-image: url(<%= asset_data_uri('user_sprite.png') %>);
|
||||
background-image: url(<%= asset_path('user_sprite.png') %>);
|
||||
}
|
||||
.accountSettings .accountIcon {
|
||||
background-position: 0 0;
|
||||
|
@ -3076,3 +3076,7 @@ script.data-gratipay-username {
|
|||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
|
@ -129,3 +129,11 @@
|
|||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.back-to-mapping {
|
||||
margin: 1em;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,10 @@
|
|||
}
|
||||
.addMap {
|
||||
background-position: -96px 0;
|
||||
margin-right:10px;
|
||||
}
|
||||
.notificationsIcon {
|
||||
background-position: -128px 0;
|
||||
margin-right: 10px; // make it look more natural next to the account menu icon
|
||||
}
|
||||
.importDialog:hover {
|
||||
background-position: 0 -32px;
|
||||
|
@ -758,7 +761,7 @@
|
|||
}
|
||||
|
||||
.exploreMapsCenter .authedApps .exploreMapsIcon {
|
||||
background-image: url(<%= asset_data_uri('user_sprite.png') %>);
|
||||
background-image: url(<%= asset_path('user_sprite.png') %>);
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
.exploreMapsCenter .myMaps .exploreMapsIcon {
|
||||
|
@ -781,6 +784,10 @@
|
|||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
||||
background-position: -96px 0;
|
||||
}
|
||||
.exploreMapsCenter .notificationsLink .exploreMapsIcon {
|
||||
background-image: url(<%= asset_path 'user_sprite.png' %>);
|
||||
background-position: 0 -128px;
|
||||
}
|
||||
.authedApps:hover .exploreMapsIcon, .authedApps.active .exploreMapsIcon {
|
||||
background-position-x: -32px;
|
||||
}
|
||||
|
@ -799,6 +806,9 @@
|
|||
.sharedMaps:hover .exploreMapsIcon, .sharedMaps.active .exploreMapsIcon {
|
||||
background-position: -128px -32px;
|
||||
}
|
||||
.notificationsLink:hover .exploreMapsIcon, .notificationsLink.active .exploreMapsIcon {
|
||||
background-position-x: -32px;
|
||||
}
|
||||
|
||||
.mapsWrapper {
|
||||
/*overflow-y: auto; */
|
||||
|
|
|
@ -213,6 +213,15 @@
|
|||
line-height: 50px;
|
||||
}
|
||||
|
||||
#mobile_header #menu_icon .unread-notifications-dot {
|
||||
top: 5px;
|
||||
left: 29px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 3px solid #eee;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
#mobile_menu {
|
||||
display: none;
|
||||
background: #EEE;
|
||||
|
@ -222,11 +231,20 @@
|
|||
padding: 10px;
|
||||
width: 200px;
|
||||
box-shadow: 3px 3px 3px rgba(0,0,0,0.23), 3px 3px 3px rgba(0,0,0,0.16);
|
||||
}
|
||||
|
||||
#mobile_menu li {
|
||||
li {
|
||||
padding: 10px;
|
||||
list-style: none;
|
||||
|
||||
&.notifications {
|
||||
position: relative;
|
||||
|
||||
.unread-notifications-dot {
|
||||
top: 17px;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
71
app/assets/stylesheets/notifications.scss.erb
Normal file
71
app/assets/stylesheets/notifications.scss.erb
Normal file
|
@ -0,0 +1,71 @@
|
|||
$unread_notifications_dot_size: 8px;
|
||||
.unread-notifications-dot {
|
||||
width: $unread_notifications_dot_size;
|
||||
height: $unread_notifications_dot_size;
|
||||
background-color: #e22;
|
||||
border-radius: $unread_notifications_dot_size / 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.upperRightUI {
|
||||
.notificationsIcon {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.controller-notifications {
|
||||
ul.notifications {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
$menu_bar_height: 6em;
|
||||
.notificationPage,
|
||||
.notificationsPage {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 1em;
|
||||
margin-top: 1em + $menu_bar_height;
|
||||
|
||||
& > .title {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 0.25em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.back {
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.notification {
|
||||
.notification-subject {
|
||||
width: 25%;
|
||||
}
|
||||
.notification-body {
|
||||
width: 50%;
|
||||
}
|
||||
.notification-read-unread {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.notification-body,
|
||||
.notification-subject,
|
||||
.notification-read-unread {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
&.unread {
|
||||
.notification-body,
|
||||
.notification-subject,
|
||||
.notification-read-unread {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,8 @@ class AccessController < ApplicationController
|
|||
def access_request
|
||||
request = AccessRequest.create(user: current_user, map: @map)
|
||||
# what about push notification to map owner?
|
||||
MapMailer.access_request_email(request, @map).deliver_later
|
||||
mail = MapMailer.access_request_email(request, @map)
|
||||
@map.user.notify(mail.subject, mail.body)
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
|
@ -37,7 +38,9 @@ class AccessController < ApplicationController
|
|||
@map.add_new_collaborators(user_ids).each do |user_id|
|
||||
# add_new_collaborators returns array of added users,
|
||||
# who we then send an email to
|
||||
MapMailer.invite_to_edit_email(@map, current_user, User.find(user_id)).deliver_later
|
||||
user = User.find(user_id)
|
||||
mail = MapMailer.invite_to_edit_email(@map, current_user, User.find(user_id))
|
||||
user.notify(mail.subject, mail.body)
|
||||
end
|
||||
@map.remove_old_collaborators(user_ids)
|
||||
|
||||
|
@ -51,7 +54,7 @@ class AccessController < ApplicationController
|
|||
# GET maps/:id/approve_access/:request_id
|
||||
def approve_access
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.approve()
|
||||
request.approve
|
||||
respond_to do |format|
|
||||
format.html { redirect_to map_path(@map), notice: 'Request was approved' }
|
||||
end
|
||||
|
@ -60,7 +63,7 @@ class AccessController < ApplicationController
|
|||
# GET maps/:id/deny_access/:request_id
|
||||
def deny_access
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.deny()
|
||||
request.deny
|
||||
respond_to do |format|
|
||||
format.html { redirect_to map_path(@map), notice: 'Request was turned down' }
|
||||
end
|
||||
|
@ -69,7 +72,7 @@ class AccessController < ApplicationController
|
|||
# POST maps/:id/approve_access/:request_id
|
||||
def approve_access_post
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.approve()
|
||||
request.approve
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
|
@ -80,7 +83,7 @@ class AccessController < ApplicationController
|
|||
# POST maps/:id/deny_access/:request_id
|
||||
def deny_access_post
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.deny()
|
||||
request.deny
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
|
@ -94,5 +97,4 @@ class AccessController < ApplicationController
|
|||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
end
|
||||
|
||||
end
|
||||
|
|
97
app/controllers/notifications_controller.rb
Normal file
97
app/controllers/notifications_controller.rb
Normal file
|
@ -0,0 +1,97 @@
|
|||
# frozen_string_literal: true
|
||||
class NotificationsController < ApplicationController
|
||||
before_action :set_receipts, only: [:index, :show, :mark_read, :mark_unread]
|
||||
before_action :set_notification, only: [:show, :mark_read, :mark_unread]
|
||||
before_action :set_receipt, only: [:show, :mark_read, :mark_unread]
|
||||
|
||||
def index
|
||||
@notifications = current_user.mailbox.notifications
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: @notifications.map do |notification|
|
||||
receipt = @receipts.find_by(notification_id: notification.id)
|
||||
notification.as_json.merge(is_read: receipt.is_read)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@receipt.update(is_read: true)
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: @notification.as_json.merge(
|
||||
is_read: @receipt.is_read
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mark_read
|
||||
@receipt.update(is_read: true)
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.json do
|
||||
render json: @notification.as_json.merge(
|
||||
is_read: @receipt.is_read
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mark_unread
|
||||
@receipt.update(is_read: false)
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.json do
|
||||
render json: @notification.as_json.merge(
|
||||
is_read: @receipt.is_read
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def unsubscribe
|
||||
unsubscribe_redirect_if_logged_out!
|
||||
check_if_already_unsubscribed!
|
||||
return if performed? # if one of these checks already redirected, we're done
|
||||
|
||||
if current_user.update(emails_allowed: false)
|
||||
redirect_to edit_user_path(current_user),
|
||||
notice: 'You will no longer receive emails from Metamaps.'
|
||||
else
|
||||
flash[:alert] = 'Sorry, something went wrong. You have not been unsubscribed from emails.'
|
||||
redirect_to edit_user_path(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unsubscribe_redirect_if_logged_out!
|
||||
return if current_user.present?
|
||||
|
||||
flash[:notice] = 'Continue to unsubscribe from emails by logging in.'
|
||||
redirect_to "#{sign_in_path}?redirect_to=#{unsubscribe_notifications_path}"
|
||||
end
|
||||
|
||||
def check_if_already_unsubscribed!
|
||||
return if current_user.emails_allowed
|
||||
|
||||
redirect_to edit_user_path(current_user), notice: 'You were already unsubscribed from emails.'
|
||||
end
|
||||
|
||||
def set_receipts
|
||||
@receipts = current_user.mailboxer_notification_receipts
|
||||
end
|
||||
|
||||
def set_notification
|
||||
@notification = current_user.mailbox.notifications.find_by(id: params[:id])
|
||||
end
|
||||
|
||||
def set_receipt
|
||||
@receipt = @receipts.find_by(notification_id: params[:id])
|
||||
end
|
||||
end
|
|
@ -1,4 +1,8 @@
|
|||
class Users::SessionsController < Devise::SessionsController
|
||||
# frozen_string_literal: true
|
||||
module Users
|
||||
class SessionsController < Devise::SessionsController
|
||||
after_action :store_location, only: [:new]
|
||||
|
||||
protected
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
|
@ -11,4 +15,11 @@ class Users::SessionsController < Devise::SessionsController
|
|||
request.referer || root_path
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def store_location
|
||||
store_location_for(User, params[:redirect_to]) if params[:redirect_to]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,13 +13,12 @@ class UsersController < ApplicationController
|
|||
|
||||
# GET /users/:id/edit
|
||||
def edit
|
||||
@user = current_user
|
||||
respond_with(@user)
|
||||
@user = User.find(current_user.id)
|
||||
end
|
||||
|
||||
# PUT /users/:id
|
||||
def update
|
||||
@user = current_user
|
||||
@user = User.find(current_user.id)
|
||||
|
||||
if user_params[:password] == '' && user_params[:password_confirmation] == ''
|
||||
# not trying to change the password
|
||||
|
@ -96,6 +95,6 @@ class UsersController < ApplicationController
|
|||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:name, :email, :image, :password, :password_confirmation)
|
||||
params.require(:user).permit(:name, :email, :image, :password, :password_confirmation, :emails_allowed)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -37,4 +37,20 @@ module ApplicationHelper
|
|||
def invite_link
|
||||
"#{request.base_url}/join" + (current_user ? "?code=#{current_user.code}" : '')
|
||||
end
|
||||
|
||||
def user_has_unread_notifications?
|
||||
return @user_has_unread_notifications unless @user_has_unread_notifications.nil?
|
||||
return (@user_has_unread_notifications = false) if current_user.nil?
|
||||
current_user.mailboxer_notification_receipts.each do |receipt|
|
||||
return (@user_has_unread_notifications = true) if receipt.is_read == false
|
||||
end
|
||||
@user_has_unread_notifications = false
|
||||
end
|
||||
|
||||
def user_unread_notification_count
|
||||
return 0 if current_user.nil?
|
||||
current_user.mailboxer_notification_receipts.reduce(0) do |total, receipt|
|
||||
receipt.is_read ? total : total + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,8 @@
|
|||
class ApplicationMailer < ActionMailer::Base
|
||||
default from: 'team@metamaps.cc'
|
||||
layout 'mailer'
|
||||
|
||||
def deliver
|
||||
raise NotImplementedError('Please use Mailboxer to send your emails.')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
require 'open-uri'
|
||||
|
||||
class User < ApplicationRecord
|
||||
acts_as_messageable # mailboxer notifications
|
||||
|
||||
has_many :topics
|
||||
has_many :synapses
|
||||
has_many :maps
|
||||
|
@ -108,4 +110,19 @@ class User < ApplicationRecord
|
|||
def settings=(val)
|
||||
self[:settings] = val
|
||||
end
|
||||
|
||||
# Mailboxer hooks and helper functions
|
||||
|
||||
def mailboxer_email(_message)
|
||||
return email if emails_allowed
|
||||
# else return nil, which sends no email
|
||||
end
|
||||
|
||||
def mailboxer_notifications
|
||||
mailbox.notifications
|
||||
end
|
||||
|
||||
def mailboxer_notification_receipts
|
||||
mailbox.receipts.includes(:notification).where(mailbox_type: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
<%= link_to "Admin", metacodes_path %>
|
||||
</li>
|
||||
<% end %>
|
||||
<li class="accountListItem accountInvite openLightbox" data-open="invite">
|
||||
<div class="accountIcon"></div>
|
||||
<span>Share Invite</span>
|
||||
</li>
|
||||
<li class="accountListItem accountApps">
|
||||
<div class="accountIcon"></div>
|
||||
<%= link_to "Apps", oauth_authorized_applications_path %>
|
||||
</li>
|
||||
<li class="accountListItem accountInvite openLightbox" data-open="invite">
|
||||
<div class="accountIcon"></div>
|
||||
<span>Share Invite</span>
|
||||
</li>
|
||||
<li class="accountListItem accountLogout">
|
||||
<div class="accountIcon"></div>
|
||||
<%= link_to "Sign Out", "/logout", id: "Logout" %>
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
<div id="header_content">
|
||||
<%= yield(:mobile_title) %>
|
||||
</div>
|
||||
<div id="menu_icon"></div>
|
||||
<div id="menu_icon">
|
||||
<% if user_has_unread_notifications? %>
|
||||
<div class="unread-notifications-dot"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mobile_menu">
|
||||
<ul>
|
||||
|
@ -49,6 +53,12 @@
|
|||
<li>
|
||||
<%= link_to "Account", edit_user_url(current_user) %>
|
||||
</li>
|
||||
<li class="notifications">
|
||||
<%= link_to "Notifications", notifications_path %>
|
||||
<% if user_has_unread_notifications? %>
|
||||
<div class="unread-notifications-dot"></div>
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "Sign Out", "/logout", id: "Logout" %>
|
||||
</li>
|
||||
|
|
|
@ -71,6 +71,17 @@
|
|||
</a><!-- end addMap -->
|
||||
<% end %>
|
||||
|
||||
<% if current_user.present? %>
|
||||
<%= link_to notifications_path, target: '_blank', class: "notificationsIcon upperRightEl upperRightIcon #{user_has_unread_notifications? ? 'unread' : 'read'}" do %>
|
||||
<div class="tooltipsUnder">
|
||||
Notifications
|
||||
</div>
|
||||
<% if user_has_unread_notifications? %>
|
||||
<div class="unread-notifications-dot"></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<!-- Account / Sign in -->
|
||||
<% if !(controller_name == "sessions" && action_name == "new") %>
|
||||
<div class="sidebarAccount upperRightEl">
|
||||
|
|
|
@ -64,9 +64,13 @@
|
|||
<p id="toast" class="toast">
|
||||
<% if devise_error_messages? %>
|
||||
<%= devise_error_messages! %>
|
||||
<% elsif notice %>
|
||||
<% end %>
|
||||
<% if notice %>
|
||||
<%= notice %>
|
||||
<% end %>
|
||||
<% if alert %>
|
||||
<%= alert %>
|
||||
<% end %>
|
||||
</p>
|
||||
<div id="loading"></div>
|
||||
</div>
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
<% end %>
|
||||
</p>
|
||||
<div id="loading"></div>
|
||||
<%= render partial: 'shared/back_to_mapping' %>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>You have a new message: <%= @subject %></h1>
|
||||
<p>
|
||||
You have received a new message:
|
||||
</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
<%= raw @message.body %>
|
||||
</p>
|
||||
</blockquote>
|
||||
<p>
|
||||
Visit <%= link_to root_url, root_url %> and go to your inbox for more info.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
You have a new message: <%= @subject %>
|
||||
===============================================
|
||||
|
||||
You have received a new message:
|
||||
|
||||
-----------------------------------------------
|
||||
<%= @message.body.html_safe? ? @message.body : strip_tags(@message.body) %>
|
||||
-----------------------------------------------
|
||||
|
||||
Visit <%= root_url %> and go to your inbox for more info.
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>You have a new reply: <%= @subject %></h1>
|
||||
<p>
|
||||
You have received a new reply:
|
||||
</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
<%= raw @message.body %>
|
||||
</p>
|
||||
</blockquote>
|
||||
<p>
|
||||
Visit <%= link_to root_url, root_url %> and go to your inbox for more info.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
You have a new reply: <%= @subject %>
|
||||
===============================================
|
||||
|
||||
You have received a new reply:
|
||||
|
||||
-----------------------------------------------
|
||||
<%= @message.body.html_safe? ? @message.body : strip_tags(@message.body) %>
|
||||
-----------------------------------------------
|
||||
|
||||
Visit <%= root_url %> and go to your inbox for more info.
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
||||
</head>
|
||||
<body>
|
||||
<% binding.pry %>
|
||||
<%= raw @notification.body.parts[1].encoded %>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,2 @@
|
|||
<% body = @notification.body.parts[0].encoded %>
|
||||
<%= body.html_safe? ? body : strip_tags(body) %>
|
|
@ -1,11 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
|
||||
</head>
|
||||
<body style="font-family: sans-serif; width: 100%; padding: 24px 16px 16px 16px; background-color: #f5f5f5; text-align: center;">
|
||||
|
||||
<div style="padding: 16px; background: white; text-align: left;">
|
||||
<div style="padding: 16px; background: white; text-align: left;">
|
||||
<% button_style = "background-color:#4fc059;border-radius:2px;color:white;display:inline-block;font-family:Roboto,Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;min-height:29px;line-height:29px;min-width:54px;outline:0px;padding:0 8px;text-align:center;text-decoration:none" %>
|
||||
|
||||
<p><span style="font-weight: bold;"><%= @request.user.name %></span> is requesting access to <span style="font-weight: bold">collaboratively edit</span> the following map:</p>
|
||||
|
@ -18,6 +11,6 @@
|
|||
<%= link_to 'Open in Metamaps', map_url(@map), target: "_blank", style: button_style %>
|
||||
|
||||
<p style="font-size: 12px;">Make sense with Metamaps</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<%= render partial: 'shared/mailer_unsubscribe_link' %>
|
||||
</div>
|
||||
|
|
|
@ -7,4 +7,4 @@ Decline [<%= deny_access_map_url(id: @map.id, request_id: @request.id) %>]
|
|||
|
||||
Make sense with Metamaps
|
||||
|
||||
|
||||
<%= render partial: 'shared/mailer_unsubscribe_link' %>
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
|
||||
</head>
|
||||
<body style="font-family: sans-serif; width: 100%; padding: 24px 16px 16px 16px; background-color: #f5f5f5; text-align: center;">
|
||||
|
||||
<div style="padding: 16px; background: white; text-align: left;">
|
||||
<div style="padding: 16px; background: white; text-align: left;">
|
||||
<% button_style = "background-color:#4fc059;border-radius:2px;color:white;display:inline-block;font-family:Roboto,Arial,Helvetica,sans-serif;font-size:12px;font-weight:bold;min-height:29px;line-height:29px;min-width:54px;outline:0px;padding:0 8px;text-align:center;text-decoration:none" %>
|
||||
|
||||
<p><span style="font-weight: bold;"><%= @inviter.name %></span> has invited you to <span style="font-weight: bold">collaboratively edit</span> the following map:</p>
|
||||
|
@ -17,6 +10,6 @@
|
|||
<%= link_to 'Open in Metamaps', map_url(@map), target: "_blank", style: button_style %>
|
||||
|
||||
<p style="font-size: 12px;">Make sense with Metamaps</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<%= render partial: 'shared/mailer_unsubscribe_link' %>
|
||||
</div>
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
Make sense with Metamaps
|
||||
|
||||
|
||||
<%= render partial: 'shared/mailer_unsubscribe_link' %>
|
||||
|
|
18
app/views/notifications/_header.html.erb
Normal file
18
app/views/notifications/_header.html.erb
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div id="exploreMapsHeader">
|
||||
<div class="exploreMapsBar exploreElement">
|
||||
<div class="exploreMapsMenu">
|
||||
<div class="exploreMapsCenter">
|
||||
<a href="<%= notifications_path %>" class="notificationsLink exploreMapsButton active">
|
||||
<div class="exploreMapsIcon"></div>Notifications
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p id="toast" class="toast">
|
||||
<% if devise_error_messages? %>
|
||||
<%= devise_error_messages! %>
|
||||
<% elsif notice %>
|
||||
<%= notice %>
|
||||
<% end %>
|
||||
</p>
|
33
app/views/notifications/index.html.erb
Normal file
33
app/views/notifications/index.html.erb
Normal file
|
@ -0,0 +1,33 @@
|
|||
<% content_for :title, 'Notifications | Metamaps' %>
|
||||
<% content_for :mobile_title, 'Notifications' %>
|
||||
|
||||
<div id="yield">
|
||||
<div class="centerContent notificationsPage">
|
||||
<h2 class="title">My Notifications</h4>
|
||||
<ul class="notifications">
|
||||
<% @notifications.each do |notification| %>
|
||||
<% receipt = @receipts.find_by(notification_id: notification.id) %>
|
||||
<li class="notification <%= receipt.is_read? ? 'read' : 'unread' %>" id="notification-<%= notification.id %>">
|
||||
<%= link_to notification_path(notification.id) do %>
|
||||
<div class="notification-subject">
|
||||
<%= notification.subject %>
|
||||
</div>
|
||||
<div class="notification-body">
|
||||
<%= notification.body.truncate(70) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="notification-read-unread">
|
||||
<% if receipt.is_read? %>
|
||||
<%= link_to 'mark as unread', mark_unread_notification_path(notification.id), remote: true, method: :put %>
|
||||
<% else %>
|
||||
<%= link_to 'mark as read', mark_read_notification_path(notification.id), remote: true, method: :put %>
|
||||
<% end %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<%= render partial: 'shared/back_to_mapping' %>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'notifications/header' %>
|
6
app/views/notifications/mark_read.js.erb
Normal file
6
app/views/notifications/mark_read.js.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
$('#notification-<%= @notification.id %> .notification-read-unread > a')
|
||||
.text('mark as unread')
|
||||
.attr('href', '<%= mark_unread_notification_path(@notification.id) %>')
|
||||
$('#notification-<%= @notification.id %>')
|
||||
.removeClass('unread')
|
||||
.addClass('read')
|
6
app/views/notifications/mark_unread.js.erb
Normal file
6
app/views/notifications/mark_unread.js.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
$('#notification-<%= @notification.id %> .notification-read-unread > a')
|
||||
.text('mark as read')
|
||||
.attr('href', '<%= mark_read_notification_path(@notification.id) %>')
|
||||
$('#notification-<%= @notification.id %>')
|
||||
.removeClass('read')
|
||||
.addClass('unread')
|
15
app/views/notifications/show.html.erb
Normal file
15
app/views/notifications/show.html.erb
Normal file
|
@ -0,0 +1,15 @@
|
|||
<% content_for :title, 'Notifications | Metamaps' %>
|
||||
<% content_for :mobile_title, 'Notifications' %>
|
||||
|
||||
<div id="yield">
|
||||
<div class="centerContent notificationPage">
|
||||
<h2 class="title"><%= @notification.subject %></h4>
|
||||
<%= @notification.body %>
|
||||
<div class="back">
|
||||
<%= link_to 'Back', notifications_path %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render partial: 'shared/back_to_mapping' %>
|
||||
</div>
|
||||
|
||||
<%= render partial: 'notifications/header' %>
|
3
app/views/shared/_back_to_mapping.html.erb
Normal file
3
app/views/shared/_back_to_mapping.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div class="centerContent back-to-mapping">
|
||||
<a href="/">Back to mapping</a>
|
||||
</div>
|
3
app/views/shared/_mailer_unsubscribe_link.html.erb
Normal file
3
app/views/shared/_mailer_unsubscribe_link.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div class="unsubscribe-link">
|
||||
<%= link_to 'Click here to unsubscribe from all Metamaps emails', unsubscribe_notifications_url %>
|
||||
</div>
|
5
app/views/shared/_mailer_unsubscribe_link.text.erb
Normal file
5
app/views/shared/_mailer_unsubscribe_link.text.erb
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
|
||||
You can unsubscribe from all Metamaps emails by visiting the following link:
|
||||
|
||||
<%= unsubscribe_notifications_url %>
|
|
@ -33,23 +33,35 @@
|
|||
<div class="nameEdit"><%= @user.name %></div>
|
||||
</div>
|
||||
<div class="changeName">
|
||||
<%= form.label :name, "Name:", :class => "firstFieldText" %>
|
||||
<%= form.label :name, "Name:", class: 'firstFieldText' %>
|
||||
<%= form.text_field :name %>
|
||||
</div>
|
||||
<div><%= form.label :email, "Email:", :class => "firstFieldText" %>
|
||||
<%= form.email_field :email %></div>
|
||||
<div>
|
||||
<%= form.label :email, "Email:", class: 'firstFieldText' %>
|
||||
<%= form.email_field :email %>
|
||||
</div>
|
||||
<div>
|
||||
<%= form.label :emails_allowed, class: 'firstFieldText' do %>
|
||||
<%= form.check_box :emails_allowed, class: 'inline' %>
|
||||
Send Metamaps notifications to my email.
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="changePass" onclick="Metamaps.Account.showPass()">Change Password</div>
|
||||
<div class="toHide">
|
||||
<div>
|
||||
<%= form.label :current_password, "Current Password:", :class => "firstFieldText" %>
|
||||
<%= password_field_tag :current_password, params[:current_password] %>
|
||||
</div>
|
||||
<div><%= form.label :password, "New Password:", :class => "firstFieldText" %>
|
||||
<%= form.password_field :password, :autocomplete => :off%></div>
|
||||
<div><%= form.label :password_confirmation, "Confirm New Password:", :class => "firstFieldText" %>
|
||||
<%= form.password_field :password_confirmation, :autocomplete => :off%></div>
|
||||
<div>
|
||||
<%= form.label :password, "New Password:", :class => "firstFieldText" %>
|
||||
<%= form.password_field :password, :autocomplete => :off%>
|
||||
</div>
|
||||
<div>
|
||||
<%= form.label :password_confirmation, "Confirm New Password:", :class => "firstFieldText" %>
|
||||
<%= form.password_field :password_confirmation, :autocomplete => :off%>
|
||||
</div>
|
||||
<div class="noChangePass" onclick="Metamaps.Account.hidePass()">Oops, don't change password</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="accountPageLoading"></div>
|
||||
<%= form.submit "Update", class: "update", onclick: "Metamaps.Account.showLoading()" %>
|
||||
<div class="clearfloat"></div>
|
||||
|
|
|
@ -8,14 +8,15 @@ Bundler.require(*Rails.groups)
|
|||
|
||||
module Metamaps
|
||||
class Application < Rails::Application
|
||||
config.active_job.queue_adapter = :delayed_job
|
||||
if ENV['ACTIVE_JOB_FRAMEWORK'] == 'sucker_punch'
|
||||
config.active_job.queue_adapter = :sucker_punch
|
||||
end
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration should go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded.
|
||||
#
|
||||
config.active_job.queue_adapter = if ENV['ACTIVE_JOB_FRAMEWORK'] == 'sucker_punch'
|
||||
:sucker_punch
|
||||
else
|
||||
:delayed_job
|
||||
end
|
||||
|
||||
# Custom directories with classes and modules you want to be autoloadable.
|
||||
config.autoload_paths << Rails.root.join('app', 'services')
|
||||
|
|
|
@ -14,19 +14,11 @@ Rails.application.configure do
|
|||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
config.action_mailer.delivery_method = :smtp
|
||||
config.action_mailer.smtp_settings = {
|
||||
address: ENV['SMTP_SERVER'],
|
||||
port: ENV['SMTP_PORT'],
|
||||
user_name: ENV['SMTP_USERNAME'],
|
||||
password: ENV['SMTP_PASSWORD'],
|
||||
domain: ENV['SMTP_DOMAIN'],
|
||||
authentication: 'plain',
|
||||
enable_starttls_auto: true,
|
||||
openssl_verify_mode: 'none'
|
||||
config.action_mailer.delivery_method = :file
|
||||
config.action_mailer.file_settings = {
|
||||
location: 'tmp/mails'
|
||||
}
|
||||
config.action_mailer.default_url_options = { host: 'localhost:3000' }
|
||||
# Don't care if the mailer can't send
|
||||
config.action_mailer.raise_delivery_errors = true
|
||||
|
||||
# Print deprecation notices to the Rails logger
|
||||
|
|
21
config/initializers/mailboxer.rb
Normal file
21
config/initializers/mailboxer.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
Mailboxer.setup do |config|
|
||||
# Configures if your application uses or not email sending for Notifications and Messages
|
||||
config.uses_emails = true
|
||||
|
||||
# Configures the default from for emails sent for Messages and Notifications
|
||||
config.default_from = 'no-reply@metamaps.cc'
|
||||
|
||||
# Configures the methods needed by mailboxer
|
||||
config.email_method = :mailboxer_email
|
||||
config.name_method = :name
|
||||
|
||||
# Configures if you use or not a search engine and which one you are using
|
||||
# Supported engines: [:solr,:sphinx]
|
||||
config.search_enabled = false
|
||||
config.search_engine = :solr
|
||||
|
||||
# Configures maximum length of the message subject and body
|
||||
config.subject_max_length = 255
|
||||
config.body_max_length = 32_000
|
||||
end
|
|
@ -20,12 +20,25 @@ Metamaps::Application.routes.draw do
|
|||
post 'events/:event', action: :events
|
||||
get :contains
|
||||
|
||||
get :request_access, to: 'access#request_access'
|
||||
get 'approve_access/:request_id', to: 'access#approve_access', as: :approve_access
|
||||
get 'deny_access/:request_id', to: 'access#deny_access', as: :deny_access
|
||||
post :access_request, to: 'access#access_request', default: { format: :json }
|
||||
post 'approve_access/:request_id', to: 'access#approve_access_post', default: { format: :json }
|
||||
post 'deny_access/:request_id', to: 'access#deny_access_post', default: { format: :json }
|
||||
get :request_access,
|
||||
to: 'access#request_access'
|
||||
get 'approve_access/:request_id',
|
||||
to: 'access#approve_access',
|
||||
as: :approve_access
|
||||
get 'deny_access/:request_id',
|
||||
to: 'access#deny_access',
|
||||
as: :deny_access
|
||||
|
||||
post :access_request,
|
||||
to: 'access#access_request',
|
||||
default: { format: :json }
|
||||
post 'approve_access/:request_id',
|
||||
to: 'access#approve_access_post',
|
||||
default: { format: :json }
|
||||
post 'deny_access/:request_id',
|
||||
to: 'access#deny_access_post',
|
||||
default: { format: :json }
|
||||
|
||||
post :access, to: 'access#access', default: { format: :json }
|
||||
|
||||
post :star, to: 'stars#create', default: { format: :json }
|
||||
|
@ -36,6 +49,15 @@ Metamaps::Application.routes.draw do
|
|||
resources :mappings, except: [:index, :new, :edit]
|
||||
|
||||
resources :messages, only: [:show, :create, :update, :destroy]
|
||||
resources :notifications, only: [:index, :show] do
|
||||
collection do
|
||||
get :unsubscribe
|
||||
end
|
||||
member do
|
||||
put :mark_read
|
||||
put :mark_unread
|
||||
end
|
||||
end
|
||||
|
||||
resources :metacode_sets, except: [:show]
|
||||
|
||||
|
@ -109,3 +131,4 @@ Metamaps::Application.routes.draw do
|
|||
get 'load_url_title'
|
||||
end
|
||||
end
|
||||
# rubocop:enable Rubocop/Metrics/BlockLength
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# This migration comes from mailboxer_engine (originally 20110511145103)
|
||||
class CreateMailboxer < ActiveRecord::Migration
|
||||
def self.up
|
||||
#Tables
|
||||
#Conversations
|
||||
create_table :mailboxer_conversations do |t|
|
||||
t.column :subject, :string, :default => ""
|
||||
t.column :created_at, :datetime, :null => false
|
||||
t.column :updated_at, :datetime, :null => false
|
||||
end
|
||||
#Receipts
|
||||
create_table :mailboxer_receipts do |t|
|
||||
t.references :receiver, :polymorphic => true
|
||||
t.column :notification_id, :integer, :null => false
|
||||
t.column :is_read, :boolean, :default => false
|
||||
t.column :trashed, :boolean, :default => false
|
||||
t.column :deleted, :boolean, :default => false
|
||||
t.column :mailbox_type, :string, :limit => 25
|
||||
t.column :created_at, :datetime, :null => false
|
||||
t.column :updated_at, :datetime, :null => false
|
||||
end
|
||||
#Notifications and Messages
|
||||
create_table :mailboxer_notifications do |t|
|
||||
t.column :type, :string
|
||||
t.column :body, :text
|
||||
t.column :subject, :string, :default => ""
|
||||
t.references :sender, :polymorphic => true
|
||||
t.column :conversation_id, :integer
|
||||
t.column :draft, :boolean, :default => false
|
||||
t.string :notification_code, :default => nil
|
||||
t.references :notified_object, :polymorphic => true
|
||||
t.column :attachment, :string
|
||||
t.column :updated_at, :datetime, :null => false
|
||||
t.column :created_at, :datetime, :null => false
|
||||
t.boolean :global, default: false
|
||||
t.datetime :expires
|
||||
end
|
||||
|
||||
#Indexes
|
||||
#Conversations
|
||||
#Receipts
|
||||
add_index "mailboxer_receipts","notification_id"
|
||||
|
||||
#Messages
|
||||
add_index "mailboxer_notifications","conversation_id"
|
||||
|
||||
#Foreign keys
|
||||
#Conversations
|
||||
#Receipts
|
||||
add_foreign_key "mailboxer_receipts", "mailboxer_notifications", :name => "receipts_on_notification_id", :column => "notification_id"
|
||||
#Messages
|
||||
add_foreign_key "mailboxer_notifications", "mailboxer_conversations", :name => "notifications_on_conversation_id", :column => "conversation_id"
|
||||
end
|
||||
|
||||
def self.down
|
||||
#Tables
|
||||
remove_foreign_key "mailboxer_receipts", :name => "receipts_on_notification_id"
|
||||
remove_foreign_key "mailboxer_notifications", :name => "notifications_on_conversation_id"
|
||||
|
||||
#Indexes
|
||||
drop_table :mailboxer_receipts
|
||||
drop_table :mailboxer_conversations
|
||||
drop_table :mailboxer_notifications
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
# This migration comes from mailboxer_engine (originally 20131206080416)
|
||||
class AddConversationOptout < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :mailboxer_conversation_opt_outs do |t|
|
||||
t.references :unsubscriber, :polymorphic => true
|
||||
t.references :conversation
|
||||
end
|
||||
add_foreign_key "mailboxer_conversation_opt_outs", "mailboxer_conversations", :name => "mb_opt_outs_on_conversations_id", :column => "conversation_id"
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_foreign_key "mailboxer_conversation_opt_outs", :name => "mb_opt_outs_on_conversations_id"
|
||||
drop_table :mailboxer_conversation_opt_outs
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
# This migration comes from mailboxer_engine (originally 20131206080417)
|
||||
class AddMissingIndices < ActiveRecord::Migration
|
||||
def change
|
||||
# We'll explicitly specify its name, as the auto-generated name is too long and exceeds 63
|
||||
# characters limitation.
|
||||
add_index :mailboxer_conversation_opt_outs, [:unsubscriber_id, :unsubscriber_type],
|
||||
name: 'index_mailboxer_conversation_opt_outs_on_unsubscriber_id_type'
|
||||
add_index :mailboxer_conversation_opt_outs, :conversation_id
|
||||
|
||||
add_index :mailboxer_notifications, :type
|
||||
add_index :mailboxer_notifications, [:sender_id, :sender_type]
|
||||
|
||||
# We'll explicitly specify its name, as the auto-generated name is too long and exceeds 63
|
||||
# characters limitation.
|
||||
add_index :mailboxer_notifications, [:notified_object_id, :notified_object_type],
|
||||
name: 'index_mailboxer_notifications_on_notified_object_id_and_type'
|
||||
|
||||
add_index :mailboxer_receipts, [:receiver_id, :receiver_type]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
# This migration comes from mailboxer_engine (originally 20151103080417)
|
||||
class AddDeliveryTrackingInfoToMailboxerReceipts < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :mailboxer_receipts, :is_delivered, :boolean, default: false
|
||||
add_column :mailboxer_receipts, :delivery_method, :string
|
||||
add_column :mailboxer_receipts, :message_id, :string
|
||||
end
|
||||
end
|
5
db/migrate/20161125175229_add_emails_allowed_to_users.rb
Normal file
5
db/migrate/20161125175229_add_emails_allowed_to_users.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddEmailsAllowedToUsers < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
add_column :users, :emails_allowed, :boolean, default: true
|
||||
end
|
||||
end
|
59
db/schema.rb
59
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20161105160340) do
|
||||
ActiveRecord::Schema.define(version: 20161125175229) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -63,6 +63,59 @@ ActiveRecord::Schema.define(version: 20161105160340) do
|
|||
t.index ["metacode_set_id"], name: "index_in_metacode_sets_on_metacode_set_id", using: :btree
|
||||
end
|
||||
|
||||
create_table "mailboxer_conversation_opt_outs", force: :cascade do |t|
|
||||
t.string "unsubscriber_type"
|
||||
t.integer "unsubscriber_id"
|
||||
t.integer "conversation_id"
|
||||
t.index ["conversation_id"], name: "index_mailboxer_conversation_opt_outs_on_conversation_id", using: :btree
|
||||
t.index ["unsubscriber_id", "unsubscriber_type"], name: "index_mailboxer_conversation_opt_outs_on_unsubscriber_id_type", using: :btree
|
||||
end
|
||||
|
||||
create_table "mailboxer_conversations", force: :cascade do |t|
|
||||
t.string "subject", default: ""
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "mailboxer_notifications", force: :cascade do |t|
|
||||
t.string "type"
|
||||
t.text "body"
|
||||
t.string "subject", default: ""
|
||||
t.string "sender_type"
|
||||
t.integer "sender_id"
|
||||
t.integer "conversation_id"
|
||||
t.boolean "draft", default: false
|
||||
t.string "notification_code"
|
||||
t.string "notified_object_type"
|
||||
t.integer "notified_object_id"
|
||||
t.string "attachment"
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.boolean "global", default: false
|
||||
t.datetime "expires"
|
||||
t.index ["conversation_id"], name: "index_mailboxer_notifications_on_conversation_id", using: :btree
|
||||
t.index ["notified_object_id", "notified_object_type"], name: "index_mailboxer_notifications_on_notified_object_id_and_type", using: :btree
|
||||
t.index ["sender_id", "sender_type"], name: "index_mailboxer_notifications_on_sender_id_and_sender_type", using: :btree
|
||||
t.index ["type"], name: "index_mailboxer_notifications_on_type", using: :btree
|
||||
end
|
||||
|
||||
create_table "mailboxer_receipts", force: :cascade do |t|
|
||||
t.string "receiver_type"
|
||||
t.integer "receiver_id"
|
||||
t.integer "notification_id", null: false
|
||||
t.boolean "is_read", default: false
|
||||
t.boolean "trashed", default: false
|
||||
t.boolean "deleted", default: false
|
||||
t.string "mailbox_type", limit: 25
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "is_delivered", default: false
|
||||
t.string "delivery_method"
|
||||
t.string "message_id"
|
||||
t.index ["notification_id"], name: "index_mailboxer_receipts_on_notification_id", using: :btree
|
||||
t.index ["receiver_id", "receiver_type"], name: "index_mailboxer_receipts_on_receiver_id_and_receiver_type", using: :btree
|
||||
end
|
||||
|
||||
create_table "mappings", force: :cascade do |t|
|
||||
t.text "category"
|
||||
t.integer "xloc"
|
||||
|
@ -264,6 +317,7 @@ ActiveRecord::Schema.define(version: 20161105160340) do
|
|||
t.integer "image_file_size"
|
||||
t.datetime "image_updated_at"
|
||||
t.integer "generation"
|
||||
t.boolean "emails_allowed", default: true
|
||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
|
||||
end
|
||||
|
||||
|
@ -279,5 +333,8 @@ ActiveRecord::Schema.define(version: 20161105160340) do
|
|||
|
||||
add_foreign_key "access_requests", "maps"
|
||||
add_foreign_key "access_requests", "users"
|
||||
add_foreign_key "mailboxer_conversation_opt_outs", "mailboxer_conversations", column: "conversation_id", name: "mb_opt_outs_on_conversations_id"
|
||||
add_foreign_key "mailboxer_notifications", "mailboxer_conversations", column: "conversation_id", name: "notifications_on_conversation_id"
|
||||
add_foreign_key "mailboxer_receipts", "mailboxer_notifications", column: "notification_id", name: "receipts_on_notification_id"
|
||||
add_foreign_key "tokens", "users"
|
||||
end
|
||||
|
|
|
@ -32,6 +32,13 @@ Run these tests to be reasonably sure that your code changes haven't broken anyt
|
|||
- Add a number of synapses to one of your maps. Reload to see if they are still there.
|
||||
- Rearrange one of your maps and save the layout. Reload to see if the layout is preserved.
|
||||
|
||||
### Unsubscribing from Notifications
|
||||
|
||||
- Log out
|
||||
- Visit /notifications/unsubscribe. It should redirect you to the login page.
|
||||
- Log in.
|
||||
- It should redirect you to the user edit page, and you should be unsubscribed.
|
||||
|
||||
### Misc
|
||||
|
||||
- Login as admin. Change metacode sets.
|
||||
|
|
Loading…
Reference in a new issue