Fix for WiNA

This commit is contained in:
David Vandorpe 2018-03-13 14:50:50 +01:00
parent b951230fa5
commit eae4a3e99c
No known key found for this signature in database
GPG key ID: 750319296238238A
21 changed files with 146 additions and 143 deletions

1
.gitignore vendored
View file

@ -16,3 +16,4 @@
!/log/.keep
/tmp
coverage/
.idea

View file

@ -3,8 +3,6 @@ source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.4'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
@ -16,7 +14,7 @@ gem 'coffee-rails', '~> 4.1.0'
# Authentication
gem 'devise'
gem 'omniauth-oauth2'
gem 'devise_cas_authenticatable'
# Authorisation
gem 'cancancan'
@ -63,6 +61,8 @@ group :development, :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'faker'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
end
group :development do
@ -86,7 +86,7 @@ group :test do
end
group :production do
gem 'mysql2', '~> 0.3.0'
gem 'pg', '~> 0.20'
end
gem 'high_voltage', '~> 2.4.0'

View file

@ -98,6 +98,9 @@ GEM
responders
thread_safe (~> 0.1)
warden (~> 1.2.3)
devise_cas_authenticatable (1.10.3)
devise (>= 1.2.0)
rubycas-client (>= 2.2.1)
diff-lcs (1.2.5)
docile (1.1.5)
domain_name (0.5.24)
@ -111,8 +114,6 @@ GEM
railties (>= 3.0.0)
faker (1.5.0)
i18n (~> 0.5)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
friendly_id (5.1.0)
activerecord (>= 4.0.0)
globalid (0.3.6)
@ -125,7 +126,6 @@ GEM
haml (>= 4.0.6, < 5.0)
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hashie (3.4.2)
high_voltage (2.4.0)
html2haml (2.0.0)
erubis (~> 2.7.0)
@ -148,7 +148,6 @@ GEM
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
jwt (1.5.1)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.3)
@ -157,28 +156,14 @@ GEM
mini_portile (0.6.2)
minitest (5.8.0)
multi_json (1.11.2)
multi_xml (0.5.5)
multipart-post (2.0.0)
mysql2 (0.3.20)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (2.9.2)
netrc (0.10.3)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0)
omniauth (~> 1.2)
orm_adapter (0.5.0)
pg (0.21.0)
purecss-rails (0.6.0)
railties (>= 3.2.6, < 5)
rack (1.6.4)
@ -209,7 +194,7 @@ GEM
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.4.2)
rdoc (4.2.0)
rdoc (4.3.0)
react-rails (1.10.0)
babel-transpiler (>= 0.7.0)
coffee-script-source (~> 1.8)
@ -243,6 +228,8 @@ GEM
rspec-support (3.3.0)
ruby_parser (3.7.1)
sexp_processor (~> 4.1)
rubycas-client (2.3.9)
activesupport
sass (3.4.18)
sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0)
@ -314,6 +301,7 @@ DEPENDENCIES
coffee-rails (~> 4.1.0)
coveralls
devise
devise_cas_authenticatable
factory_girl_rails
faker
friendly_id (~> 5.1.0)
@ -322,8 +310,7 @@ DEPENDENCIES
jbuilder (~> 2.0)
jquery-datatables-rails
jquery-rails
mysql2 (~> 0.3.0)
omniauth-oauth2
pg (~> 0.20)
purecss-rails
rails (= 4.2.4)
react-rails
@ -339,4 +326,4 @@ DEPENDENCIES
web-console (~> 2.0)
BUNDLED WITH
1.13.7
1.16.1

View file

@ -41,16 +41,22 @@ Amount = React.createFactory React.createClass
}
Peer = React.createFactory React.createClass
extractName: (peer) ->
if peer && typeof peer == 'object'
return peer.name
return peer;
onChange: (ref) ->
@props.setPeer ref.target.value
options: ->
{ peer, peers } = @props
if peer == '' or peers.includes(peer)
peerName = @extractName(peer)
if peer == '' or peers.filter((t) -> t.name == peerName ).length > 0
[]
else
re = new RegExp peer
re = new RegExp peerName
peers.filter (s) ->
s.match(re) != null
s.name.match(re) != null
inputClass: (n) ->
c = ['form-control', 'input-lg']
c.push 'active' if n > 0
@ -66,15 +72,15 @@ Peer = React.createFactory React.createClass
input {
className: @inputClass(options.length),
onChange: @onChange,
placeholder: 'Zeus member',
placeholder: 'WiNA member',
type: 'text',
value: (@props.peer || '')
value: (@extractName(@props.peer) || '')
}
if options.length != 0
div className: 'suggestions',
@options().map (s, i) =>
div className: 'suggestion', key: i, onClick: @setPeer(s),
s
s.name
Message = React.createFactory React.createClass
onChange: (ref) ->
@ -141,11 +147,11 @@ Step = React.createFactory React.createClass
return
if giving
debtor = user.name
creditor = peer
debtor = user.username
creditor = peer.username
else
debtor = peer
creditor = user.name
debtor = peer.username
creditor = user.username
$('<input />')
.attr('name', 'transaction[debtor]')
@ -175,7 +181,7 @@ Step = React.createFactory React.createClass
unless message && message != ""
errors['message'] = 'Please fill in a message.'
unless peer && peers.includes(peer) && peer != user
unless peer && peers.filter((t) -> t.name == peer.name ).length > 0 && peer != user
errors['peer'] = 'Please select a valid Zeus member.'
errors

View file

@ -1,10 +0,0 @@
class CallbacksController < Devise::OmniauthCallbacksController
def zeuswpi
@user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect @user
end
def after_omniauth_failure_path_for(scope)
root_path
end
end

View file

@ -6,7 +6,7 @@ class TransactionsQuery
@transactions = Arel::Table.new(:transactions)
@perspectived = Arel::Table.new(:perspectived_transactions)
@peers = Arel::Table.new(:users).alias('peers')
@arel_table = Arel::Table.new("#{@user.name}_transactions")
@arel_table = Arel::Table.new("#{@user.username}_transactions")
end
def query
@ -16,7 +16,7 @@ class TransactionsQuery
def arel
Arel::Nodes::TableAlias.new(
issued_by(User).union(:all, issued_by(Client)),
issued_by(User),
arel_table.name
)
end

View file

@ -36,8 +36,8 @@ class TransactionsController < ApplicationController
.permit(:debtor, :creditor, :message, :euros, :cents, :id_at_client)
{
debtor: t[:debtor] ? User.find_or_create_by(name: t[:debtor]) : User.zeus,
creditor: t[:creditor] ? User.find_or_create_by(name: t[:creditor]) : User.zeus,
debtor: t[:debtor] ? User.find_by(username: t[:debtor]) : User.wina,
creditor: t[:creditor] ? User.find_by(username: t[:creditor]) : User.wina,
issuer: current_client || current_user,
amount: (t[:euros].to_f * 100 + t[:cents].to_f).to_i,
message: t[:message],

View file

@ -14,7 +14,7 @@ class Client < ActiveRecord::Base
has_many :issued_transactions, as: :issuer, class_name: 'Transaction'
before_create :generate_key
validates :name, presence: true, uniqueness: true
validates :username, presence: true, uniqueness: true
private
def generate_key

View file

@ -13,7 +13,7 @@
class User < ActiveRecord::Base
include FriendlyId
friendly_id :name, use: :finders
devise :timeoutable, :omniauthable, :omniauth_providers => [:zeuswpi]
devise :cas_authenticatable
has_many :incoming_transactions,
class_name: 'Transaction', foreign_key: 'creditor_id'
has_many :outgoing_transactions,
@ -28,7 +28,7 @@ class User < ActiveRecord::Base
validates :name, presence: true, uniqueness: true
scope :humans, -> { where.not(id: self.zeus) }
scope :humans, -> { where.not(id: self.wina) }
def transactions
Transaction.where("creditor_id = ? OR debtor_id = ?", id, id)
@ -40,14 +40,13 @@ class User < ActiveRecord::Base
self.update_attribute :balance, balance
end
def self.from_omniauth(auth)
where(name: auth.uid).first_or_create do |user|
user.name = auth.uid
end
def cas_extra_attributes=(extra_attributes)
self.name = extra_attributes['display_name']
self.debt_allowed = extra_attributes['permissions'].include? 'HAVE_SCHULDEN'
self.penning = extra_attributes['permissions'].include? 'MANAGE_SCHULDEN'
end
def self.zeus
@@zeus ||= find_or_create_by name: 'Zeus'
def self.wina
@@wina ||= find_or_create_by name: 'WiNA', username: :WiNA
end
end

View file

@ -1,3 +1,3 @@
.card-wrapper
.card.padded
= react_component 'TransactionForm', user: current_user, peers: User.all.order(:name).pluck(:name)
= react_component 'TransactionForm', user: current_user, peers: User.all.order(:name)

View file

@ -4,7 +4,7 @@
.pure-u-1.pure-u-md-1-2
%h2 Authentication
%p Log een keer in en betaal uw schulden!
%p= link_to "Log in met Zeus WPI", user_omniauth_authorize_path(:zeuswpi), class: "pure-button pure-button-primary login-button"
%p= link_to "Log in met WiNA CAS", new_user_session_path, class: "pure-button pure-button-primary login-button"
.pure-u-1.pure-u-md-1-2
%h2 Pie of Shame
= pie_chart @statistics.shamehash

View file

@ -3,9 +3,9 @@
= render 'partials/form_errors', object: @transaction
= form_for @transaction, remote: true, html: { class: "pure-form form-inline" } do |f|
= f.hidden_field :debtor, value: @user.name
= f.hidden_field :debtor, value: @user.username
= f.select :creditor,
options_from_collection_for_select(User.all.order(:name), :name, :name),
options_from_collection_for_select(User.all.order(:name), :username, :name),
{ include_blank: true },
{ class: 'select2-selector', required: true, data: { placeholder: "Creditor", width: 150 } }
= f.text_field :message, placeholder: "Message", size: 75, class: "form-control", required: true

View file

@ -42,13 +42,13 @@
.row
.col-md-4
.input-listen{ 'data-input-type': 'text', 'data-filter-name': 'Issuer' }
= grouped_collection_select nil, nil, [User, Client], :all, :name, :name, :name,
= grouped_collection_select nil, nil, [User, Client], :all, :name, :username, :name,
{ include_blank: true },
{ data: { placeholder: "Filter on Issuer", width: 265 }, class: "select2-selector form-control value-thing" }
.col-md-4
.input-listen{ 'data-input-type': 'text', 'data-filter-name': 'Peer' }
= select_tag nil,
options_from_collection_for_select(User.all.order(:name), :name, :name),
options_from_collection_for_select(User.all.order(:name), :username, :name),
include_blank: true, class: "select2-selector form-control value-thing", data: { placeholder: "Filter on Peer", width: 265 }
.col-md-4
.input-listen{ 'data-input-type': 'text', 'data-filter-name': 'Message' }

View file

@ -1,8 +1,4 @@
#!/usr/bin/env ruby
begin
load File.expand_path("../spring", __FILE__)
rescue LoadError
end
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'

View file

@ -1,8 +1,4 @@
#!/usr/bin/env ruby
begin
load File.expand_path("../spring", __FILE__)
rescue LoadError
end
require_relative '../config/boot'
require 'rake'
Rake.application.run

View file

@ -4,9 +4,9 @@ Devise.setup do |config|
# The secret key used by Devise. Devise uses this key to generate
# random tokens. Changing this key will render invalid all existing
# confirmation, reset password and unlock tokens in the database.
# Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key`
# Devise will use the `secret_key_base` as its `secret_key`
# by default. You can change it below and use your own secret key.
# config.secret_key = 'db9dcc69d4370aba9151d435032f8263c40b2536a288267af3878a16df4b9d9f8e509f7671a39c534d0ac663f6fb9d3a879cdea867dc73053c97b36406e0a9e9'
# config.secret_key = 'a53f0fd5c5917bd1c1453a26597c4b8767ec02ae7e716f2c5513c389b5441a2a5fdd3ed82561f29579f05c6d2242979cbc7836d63bb1f38e1ab6f2c2d8ccc934'
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
@ -17,6 +17,9 @@ Devise.setup do |config|
# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
# Configure the parent class responsible to send e-mails.
# config.parent_mailer = 'ActionMailer::Base'
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
@ -87,19 +90,31 @@ Devise.setup do |config|
# from the server. You can disable this option at your own risk.
# config.clean_up_csrf_token_on_authentication = true
# When false, Devise will not attempt to reload routes on eager load.
# This can reduce the time taken to boot the app but if your application
# requires the Devise mappings to be loaded during boot time the application
# won't boot properly.
# config.reload_routes = true
# ==> Configuration for :database_authenticatable
# For bcrypt, this is the cost for hashing the password and defaults to 10. If
# using other encryptors, it sets how many times you want the password re-encrypted.
# For bcrypt, this is the cost for hashing the password and defaults to 11. If
# using other algorithms, it sets how many times you want the password to be hashed.
#
# Limiting the stretches to just one in testing will increase the performance of
# your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
# a value less than 10 in other environments. Note that, for bcrypt (the default
# encryptor), the cost increases exponentially with the number of stretches (e.g.
# algorithm), the cost increases exponentially with the number of stretches (e.g.
# a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
config.stretches = Rails.env.test? ? 1 : 10
config.stretches = Rails.env.test? ? 1 : 11
# Setup a pepper to generate the encrypted password.
# config.pepper = '6246d8fa4efd376623925a6d8600b268d11ce906a667d550663fe069dbe249bd11c0f26329c1d61f58fa9a615ee738d5b0feba189b6fdc390662e45b7a39c476'
# Set up a pepper to generate the hashed password.
# config.pepper = 'c664e685c6d19495baa24a50ea811daca5acc07987f86748699ccc1f31dcae70b39744352188041ea10428d923ef58228fb93c829672e2065be91784909dd2d5'
# Send a notification to the original email when the user's email is changed.
# config.send_email_changed_notification = false
# Send a notification email when the user's password is changed.
# config.send_password_change_notification = false
# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
@ -142,12 +157,12 @@ Devise.setup do |config|
# ==> Configuration for :validatable
# Range for password length.
config.password_length = 8..72
config.password_length = 6..128
# Email regex used to validate email formats. It simply asserts that
# one (and only one) @ exists in the given string. This is mainly
# to give user feedback and not to assert the e-mail validity.
# config.email_regexp = /\A[^@]+@[^@]+\z/
config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
@ -195,11 +210,11 @@ Devise.setup do |config|
# config.sign_in_after_reset_password = true
# ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
# :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
# :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
# and :restful_authentication_sha1 (then you should set stretches to 10, and copy
# REST_AUTH_SITE_KEY to pepper).
# Allow you to use another hashing or encryption algorithm besides bcrypt (default).
# You can use :sha1, :sha512 or algorithms from others authentication tools as
# :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20
# for default behavior) and :restful_authentication_sha1 (then you should set
# stretches to 10, and copy REST_AUTH_SITE_KEY to pepper).
#
# Require the `devise-encryptable` gem when using anything other than bcrypt
# config.encryptor = :sha512
@ -235,7 +250,7 @@ Devise.setup do |config|
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
config.omniauth :zeuswpi, Rails.application.secrets.omniauth_client_id, Rails.application.secrets.omniauth_client_secret
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
@ -259,4 +274,51 @@ Devise.setup do |config|
# When using OmniAuth, Devise cannot automatically set OmniAuth path,
# so you need to do it manually. For the users scope, it would be:
# config.omniauth_path_prefix = '/my_engine/users/auth'
config.cas_base_url = 'https://login.wina-gent.be/cas'
# you can override these if you need to, but cas_base_url is usually enough
# config.cas_login_url = "https://cas.myorganization.com/login"
# config.cas_logout_url = "https://cas.myorganization.com/logout"
# config.cas_validate_url = "https://cas.myorganization.com/serviceValidate"
# The CAS specification allows for the passing of a follow URL to be displayed when
# a user logs out on the CAS server. RubyCAS-Server also supports redirecting to a
# URL via the destination param. Set either of these urls and specify either nil,
# 'destination' or 'follow' as the logout_url_param. If the urls are blank but
# logout_url_param is set, a default will be detected for the service.
# config.cas_destination_url = 'https://cas.myorganization.com'
# config.cas_follow_url = 'https://cas.myorganization.com'
# config.cas_logout_url_param = nil
# You can specify the name of the destination argument with the following option.
# e.g. the following option will change it from 'destination' to 'url'
# config.cas_destination_logout_param_name = 'url'
# By default, devise_cas_authenticatable will create users. If you would rather
# require user records to already exist locally before they can authenticate via
# CAS, uncomment the following line.
# config.cas_create_user = false
# You can enable Single Sign Out, which by default is disabled.
# config.cas_enable_single_sign_out = true
# If you don't want to use the username returned from your CAS server as the unique
# identifier, but some other field passed in cas_extra_attributes, you can specify
# the field name here.
# config.cas_user_identifier = nil
# If you want to use the Devise Timeoutable module with single sign out,
# uncommenting this will redirect timeouts to the logout url, so that the CAS can
# take care of signing out the other serviced applocations. Note that each
# application manages timeouts independently, so one application timing out will
# kill the session on all applications serviced by the CAS.
# config.warden do |manager|
# manager.failure_app = DeviseCasAuthenticatable::SingleSignOut::WardenFailureApp
# end
# If you need to specify some extra configs for rubycas-client, you can do this via:
# config.cas_client_config_options = {
# logger: Rails.logger
# }
end

View file

@ -1,38 +0,0 @@
require 'omniauth-oauth2'
module OmniAuth
module Strategies
class Zeuswpi < OmniAuth::Strategies::OAuth2
option :provider_ignores_state, true
# Give your strategy a name.
option :name, 'zeuswpi'
# This is where you pass the options you would pass when
# initializing your consumer from the OAuth gem.
option :client_options, {
site: 'https://adams.ugent.be',
authorize_url: '/oauth/oauth2/authorize/',
token_url: '/oauth/oauth2/token/',
}
# These are called after authentication has succeeded. If
# possible, you should try to set the UID without making
# additional calls (if the user id is returned with the token
# or as a URI parameter). This may not be possible with all
# providers.
uid{ raw_info['username'] }
extra do
{
'raw_info' => raw_info
}
end
def raw_info
@raw_info ||= access_token.get('/oauth/api/current_user/').parsed
end
end
end
end

View file

@ -1,7 +1,5 @@
Rails.application.routes.draw do
devise_for :users, controllers: {
omniauth_callbacks: 'callbacks'
}
devise_for :users
devise_scope :user do
delete '/sign_out', to: 'devise/sessions#destroy'

View file

@ -1,8 +1,12 @@
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :name, index: true, unique: true
t.string :username, index: true, unique: true
t.integer :balance, null: false, default: 0, index: true
t.string :name, null: false
t.boolean :debt_allowed, null: false, default: false
t.boolean :penning, null: false, default: false
t.timestamps null: false

View file

@ -1,7 +1,7 @@
class CreateClients < ActiveRecord::Migration
def change
create_table :clients do |t|
t.string :name, null: false, index: true, unique: true
t.string :username, null: false, index: true, unique: true
t.string :key, null: false, index: true, unique: true
t.timestamps null: false

View file

@ -14,14 +14,14 @@
ActiveRecord::Schema.define(version: 20170123151219) do
create_table "clients", force: :cascade do |t|
t.string "name", null: false
t.string "username", null: false
t.string "key", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "clients", ["key"], name: "index_clients_on_key"
add_index "clients", ["name"], name: "index_clients_on_name"
add_index "clients", ["username"], name: "index_clients_on_username"
create_table "clients_roles", id: false, force: :cascade do |t|
t.integer "client_id"
@ -85,14 +85,16 @@ ActiveRecord::Schema.define(version: 20170123151219) do
add_index "transactions", ["issuer_type", "issuer_id"], name: "index_transactions_on_issuer_type_and_issuer_id"
create_table "users", force: :cascade do |t|
t.string "name"
t.string "username"
t.integer "balance", default: 0, null: false
t.string "name", null: false
t.boolean "debt_allowed", default: false, null: false
t.boolean "penning", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["balance"], name: "index_users_on_balance"
add_index "users", ["name"], name: "index_users_on_name"
add_index "users", ["username"], name: "index_users_on_username"
end