authorizing specific controller action using cancancan - ruby-on-rails-4.1

I have link to access player's load_player view to access player that belongs to current_user. So how can i restrict access to load_player method for current_user that has no belonging club or club belonging to other user. Note I want restrict access to load_player page.
routes.rb
get 'player/load_player/:id' => "player#load_player", as: :player
# player_controller.rb
class PlayerController < ApplicationController
before_action :authenticate_user!
authorize_resource :class => false
layout "player"
def load_player
#club_hash = Club.where({:id => params[:id]}).pluck(:club_hash).first
end
end
# ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.is?(:admin)
can :manage, :all
elsif user.is?(:owner)
can :read, all: { except: [UploadedSong]}
can :manage, Club, user_id: user.id
can :read, :load_player, id: user.id
elsif user.is?(:user)
can :read, all: { except: [UploadedSong]}
end
end
end

current_user.clubs.where(id: params[:id]).pluck(:club_hash).try(:first)
# or add user_id inside where clause
Club.where(id: params[:id], user_id: current_user.id).pluck(:club_hash).try(:first)
Hope this solve your problem :)

Related

ORACLE APEX: How do I prevent reloading of the login page when I use submit page action?

They request me that when a common user logs in, I must validate user and password for access to the system but when user is admin, I must validate user, password and a token that the system send to email user's (2FA).
I have created a process that handles:
-validate if the username and password are correct
-Obtains the type of user, if it is a common user it redirects him to the first page, otherwise it sends a token to his email.
PROCEDURE PRC_PROCESA_LOGIN(p_username VARCHAR2, p_password VARCHAR2, p_app_id NUMBER, p_ip_cliente VARCHAR2) IS
l_rt_autenticacion_resultado rt_autenticacion_resultado;
l_enable_2fa number;
l_tipo_usuario VARCHAR2(1);
e_error exception;
BEGIN
l_rt_autenticacion_resultado := pkg_eir_seguridad_2.FNC_AUTENTICAR_USUARIO(p_username, p_password, p_ip_cliente);
SELECT SC.Enable_2fa INTO l_enable_2fa FROM OF_SERVER_CONFIG SC;
IF l_rt_autenticacion_resultado.exito THEN
SELECT tipo_usuario
INTO l_tipo_usuario
FROM of_usuario u
WHERE u.cod_usuario =
l_rt_autenticacion_resultado.usuario_autenticado_id;
IF (l_enable_2fa = 1 AND l_tipo_usuario = 'B') THEN
l_rt_autenticacion_resultado.exito := FNC_GENERAR_TOKEN_2AF(p_username, p_password);
IF l_rt_autenticacion_resultado.exito = TRUE THEN
apex_util.set_session_state('APP_2FA', 1);
END IF;
ELSE
apex_util.set_session_state('APP_USUARIO_AUTENTICADO_ID', l_rt_autenticacion_resultado.usuario_autenticado_id);
Wwv_Flow_Custom_Auth_Std.Post_Login(p_username,
p_password,
v('APP_SESSION'),
p_App_Id || ':1');
END IF;
ELSE
apex_util.set_session_state('APP_AUTENTICACION_RESULTADO_MENSAJE',
l_rt_autenticacion_resultado.mensaje);
apex_util.set_custom_auth_status(l_rt_autenticacion_resultado.mensaje);
--raise_application_error(-20001, l_rt_autenticacion_resultado.mensaje);
END IF;
END;
I have created an AD event type: click, action: Execute Server-side code and place the procedure
I tried with a common user but when I click the LOGIN button, it does not perform the redirection
I have created an AD LOGIN button:
event: click,
action: Execute Server-side code
PL/SQL Code:
begin
PKG_EIR_SEGURIDAD.PRC_PROCESA_LOGIN(p_username => :P9999_USERNAME,
p_password => to_char(:P9999_PASSWORD),
p_app_id => :APP_ID,
p_ip_cliente => owa_util.get_cgi_env ('REMOTE_ADDR'));
end;
I tried with a common user but when I click the LOGIN button it does not perform the redirection.
I have placed this same procedure in Processing. I tried with the same common user and if it redirects it to the home page.
button login:
-Behavior accion: Submit page
Processing:
-Processes Name: Login
-Type: Execute Code
-PL/SQL: (same code above)
My problem is that when I try with an administrator user the page is reloaded and deletes the credentials that the user I had already entered. My idea is that when the user is an administrator, the process returns false but leaves the values, then through an AD enable the 2FA region that has the item P9999_TOKEN and the VALIDATE button. When the user enters the token and clicks on the VALIDATE button, this must call a procedure that validates
that the token is correct and redirects it to the home page.
How could I solve this problem or what should I do to find a solution?
Here is one option. I have not verified it with a custom authentication script but you should be able to fill in the blanks. The idea is to do it all in the login page and not in the authentication procedure and also not to submit the login page until token is verified. reloading the login page with the entered value could be a security issue.
On the login page:
add 2 additional page items: P9999_TOKEN (text field) and P9999_TOKEN_NEEDED (hidden, value protected)
add a dynamic action (DA) on page load to hide P9999_TOKEN
add a dynamic action on change of P9999_USERNAME
add true action of type serverside code (items to return P9999_TOKEN_NEEDED) to check if the user needs to enter the token. Set the value to Y or N depending on the outcome. If the outcome is Y, then send the token value email in this pl/sql block - you know who the user is.
add a true action to show the P9999_TOKEN (client condition javascript expression, apex.item('P9999_TOKEN_NEEDED').getValue() == 'Y'
add a validation with serverside conditon item = value, P9999_TOKEN_NEEDED = Y to validate the token. If the token is invalid, validation fails and the page is not submitted so user never logs on.

Firebase - snapshot based on ids

I've been looking everywhere for the logic to build a specific request, but I don't completely get the firebase philosophy. This is my data structure:
`users:{
u1_id:{...}
u2_id:{...}
...
},
contacts:{
u1_id:{
contact1_id,
contact2_id,
...
}
}`
My first option would be a request that gets the data regarding the user id, the second one (the actual one) is to store the data I need from the contacts when they're added but I would need to run a big update for each contacts of each user and that doesn't seem to be the right solution. (I've check questions, firebase doc and videos)
The closest solution I found is this (from their youtube):
function getUserContacts(key, cb){
const rootRef = firebase.database().ref()
const contactsRef = rootRef.child('contacts')
const usersRef = rootRef.child('users')
contactsRef.child(key).on('child_added', snap => {
let userRef = usersRef.child(snap.key)
userRef.once('value', cb)
})
}
but it gives the users 1 by 1 and not an object with all my users
Edit: my temporary solution ->
firebase.database().ref('users')
.on('value', snaps => {
firebase.database().ref(`contacts/${currentUser.uid}`)
.on('value', snapshot => {
let userContacts = []
snapshot.forEach(snapc => {
snaps.forEach(snapu => {
let duser = snapu
if(snapc.key == snapu.key)
{
userContacts.push(snapu.val())
}
})
})
dispatch({
type: CONTACTS_FETCH,
payload: userContacts
})
})
})
The question is still a bit unclear but let me present three options:
If we want to populate a list with user_1's contacts, we read in the users contacts node by value. In this case, user_1 has two contacts; user_id2 and user_id3
contacts
user_1
user_id2: true
user_id3: true
Value reads in the parent node (user_1) with all of the child data as well. Because we have the entire node of data (a snapshot) we can iterate over the child values of user_1 to obtain each user_idx (which is the key of each child node). As you iterate over the children, each will present a key, to which you can then read in that specific user node.
A second option is to change the structure.
contacts
user_2
name: "John"
rank: "Captain"
contact_of: "user_1"
user_3
name: "William"
rank: "Second Officer"
contact_of: "user_1"
with this structure, if user 1 wants to load their contacts, a simple query on the contacts node where contact_of = "user_1". That would load each contact and all of their data.
This second example works when a user has specific contacts that are not shared.
If multiple users can have multiple contacts, here's another option.
contacts
user_2
name: "Jean Luc"
rank: "Captain"
contact_of
user_1: true
user_2: true
user_3
name: "William"
rank: "Second Officer"
contact_of:
user_1: true
user_2: true
in this case, perform a deep query on the contacts node where contact_of/user_1 = true, which will present user_2 and user_3/

NoSQL Firebase denormalization

So I just recently learn about denormalization and I am just trying to figure out the best way to structure my firebase database. What I currently have is I am displaying a users class schedule with the classes course number and intructor name. Firebase looks like this for me:
-root
-users
-uid1
-uid2
-schedules
-uid1 : true (match with users uid)
-uid2 : true (match with users uid)
-class
-classKey1
-users
-uid1 : true
-uid2 : true
-courseKey1 : true
-intructorKey1 : true
-classKey1
-users
-uid1
-courseKey2 : true
-intructorKey2 : true
-courses
-courseKey1
-intructors
-intructorKey1 : true
-intructorKey2 : true
-courseKey2
-similar to above
-intructors
-intructorKey1
-courses
-courseKey1: true
-courseKey2: true
-intructorKey2
-similar to above
Now, that is the basic structure of what I am working with, excluding all the unneeded information. Lets say I want to display all of the the schedule of the currently logged in user I will need to do the following.
_af.auth.subscribe(authState => {
let userID = authState.uid;
_af.database.list('/schedule/' + userID ).subscribe(schedule =>{
this.schedule = schedule; //global variable
this.filterClasses(); call function
});
});
_af.database.list('/class').subscribe(classes => {
this.masterClasses = classes; //gloabal variable
this.filterClasses();
});
Now because its all done asynchronously the only way I could think to do this is call the filterClasses function inside of each subscription.
filterClasses(): void {
if (this.scheduleKeys != null && this.masterClasses.length > 0) {
this.outputClasses = this.masterClasses.filter(value => {
let bool = false;
for (let i = 0; i < this.scheduleKeys.length; i++) {
if (this.scheduleKeys[i].$key === value.$key) {
bool = true;
break;
}
}
return bool;
});
this.outputClasses.forEach((value, i) => {
_af.database.object('courses/' + value.courseKey).subscribe(v => {
this.outputClasses[i]['courseNum'] = v.course;
})
_af.database.object('intructors/' + value.intructorKey).subscribe(v => {
this.outputClasses[i]['intructorName'] = v.name;
})
})
}
}
As you can see when I am done filtering my master list of classes into just the ones in my schedule I also now need to go and grab the course number firebase and the intructors name. Both of which require me to call firebase again. So to try and reduce researching firebase which seems to be causing some problems due to being async should I instead be denormalizing my data? Should in the class root of firebase instead of storing just courseKey1 should I store all the data associated to couseKey1? However, this will cause rooting in firebase because if I structure this way now in my courses root when I say the intructors key instead of just saving the key I would save everything which is just another level deeper firebase goes.
This is kind of an indirect answer:
Denormalizing data is a good thing but in same cases it may not be necessary.
For example in this case a student wants to know his courses, so you know the direct path to the student; users/uid_0 and then maybe a query for the semester you are interested in.
Here's a structure that goes with your courses and instructors
users
uid_0
schedules
-Yiaiajsdaoiojasd
semester: 1
courses
course1: true
course3: true
-Jyuhus99jsijskkss
semester: 2
courses
course2: true
course4: true
uid_1
schedules
-Yjs909k0s0s0ks0s
semester: 1
courses
course1: true
course3: true
-Jyuhus99jsijskkss
semester: 2
courses
course2: true
course4: true
This really isn't very deep since once you read in the user node, you have specific paths to the other data you need: /courses/courseKey1/instructors for example, then followed by instructors/instructor1/name.
Where you get into trouble is if you DON'T know the direct path to the data and have to pile up queries on queries - that's where denormalizing is most effective. Also, queries have lot of overhead vs just observing a node at a path you know.

Elm: Iterate list performing multiple HTTP requests

I'm wondering if I can get some help with iterating a list of groups, making a POST request for each group to create a 'room', iterating the users for each group and making a POST request to assign them to this specific room.
I have the following model.
model = {
groups = [
{
title = "Foo"
, users = [
{ name = "Joe" }
, { name = "Mary" }
]
},
{
title = "Bar"
, users = [
{ name = "Jill" }
, { name = "Jack" }
]
}
]
}
The desired result is that the room Foo was created and Joe and Mary were assigned, and Bar was created and Jill and Jack were assigned.
The view, for now, would just be a simple button that triggers an action.
div []
[ button [ onClick InviteUsersToRoom ] [ text "Invite users to room" ] ]
I've created 2 POST requests:
createRoom: take a title, create a room using the title and return the room_id
addUser: take a room_id and a user's name, add the the users to the room and return the status of ok
example:
-- create a room for each group
-- passing in `title` as the room name
-- which will return the room id from `decodeCreateRoomResponse`
createRoom : String -> String -> Cmd Msg
createRoom title =
Task.perform
CreateRoomsFail
CreateRoomsSuccess
(Http.post
decodeCreateRoomResponse
("https://some_api?room=" ++ title)
Http.empty
)
decodeCreateRoomResponse : Json.Decoder String
decodeCreateRoomResponse =
Json.at ["room", "id"] Json.string
-- add a user to a room using a `room_id` and the user's name
-- returns a bool from `decodeAddUserResponse`
addUser : String -> String -> Cmd Msg
addUser room_id user =
Task.perform
AddUserFail
AddUserSuccess
(Http.post
decodeCreateChannelResponse
("https://some_api?room=" ++ room_id ++ "&user=" ++ user)
Http.empty
)
decodeAddUserResponse : Json.Decoder String
decodeAddUserResponse =
Json.at ["ok"] Json.bool
I'm wondering how you'd go about stitching this up altogether, so that onclick :
iterate each group
make the POST to create the Room
take the room_id from the response and iterate the users
POST the room_id and the users name
Any help is appreciated.
You've got a few scattered errors that I won't explicitly point out because the compiler will help you, but you're off to a good start. You already have some Http handling Cmds built up so you just need to wire things up with your update function.
Let's define your Model explicitly (you may already be doing this but it isn't in your example):
type alias User =
{ name : String }
type alias Group =
{ title : String
, users : List User
}
type alias Model =
{ groups : List Group }
Based off your functions, here's how I interpret your Msg type, with one small change which is to add a list of users as a parameter to CreateRoomsSuccess.
type Msg
= InviteUsersToRoom
| CreateRoomsFail Http.Error
| CreateRoomsSuccess (List User) String
| AddUserFail Http.Error
| AddUserSuccess Bool
Now we can tweak createRoom in order to pass along the list of users to create. Note that this isn't creating any users at this time. It is using currying to create a partially-applied function so that when the CreateRoomsSuccess case is handled in the update function, it already has the list of users that need to be created (rather than having to look them up in the model list):
createRoom : Group -> Cmd Msg
createRoom group =
Task.perform
CreateRoomsFail
(CreateRoomsSuccess group.users)
(Http.post
decodeCreateRoomResponse
("https://some_api?room=" ++ group.title)
Http.empty
)
To create the list of rooms, you simply map the list of groups to a list of Cmds that perform the post. This will happen when the button is clicked:
case action of
InviteUsersToRoom ->
model ! List.map createRoom model.groups
...
You'll have to implement the update cases for when errors occur. Next up, we have to handle the CreateRoomsSuccess message. This is where you'll need to look up the list of users for a group. Again, you'll map over the function you already created that handles the Http task:
case action of
...
CreateRoomsSuccess users roomID ->
model ! List.map (addUser roomID << .name) users
...
You'll have to handle the AddUserFail and AddUserSuccess cases, but the above examples should help you understand how to post multiple messages and act accordingly based on the success or failure of each.

Nested requests with Scala and play Framework

I'm working with Play Framework (2.0.4) and Scala, and I have a problem.
I call my backend to get a list of users (in json), and for each user, I have to get extra info from the backend (one request per user).
So in my services, I have :
def getUsers(/*different uninteresting parameters*/ ): Promise[List[Option[User]]]
and
def getExtraUserInfo(user:User):Promise[Option[Double]]
So for each User which is returned by getUsers, I want to call getExtraUserInfo, and return the user plus the extra info about each user.
So in my controller, i've tried to do something like that :
def getUsers(/*parameters*/) = AuthenticatedAsync{ request =>
val users = UserService.getUsers(/*parameters*/)
users.flatMap {
case Some(userList) =>
Ok(Success("users" -> Json.toJson(userList.flatMap{
user => UserService.getExtraUserInfo(user).map {
case Some(price) => user.price = price
user
case _ => user
}
}.map(_.json))))
case _ => InternalServerError(Error("error while getting users", Errors.TECHNICAL))
}
}
Do you guys have any idea how to do it ? (this code doesn't work, but that's all I managed to do...)
Try Promise.sequence to sequence a list of promise.
Promise.sequence transforms a List[Promise[T]] to a Promise[List[T]]...
see the Play! Scala API here

Resources