How to use a Model object across a number of Controllers? - asp.net-mvc-4

SCENARIO: After the user has successfully logged in, I want to create an Account object (Account class is a part of my model) and fetch and store the user's information in it. I want this Account object to be accessible to all my controllers (HomeController, AccountController etc) and also, I want the ability to edit its content from inside any controller. (1) How can I achieve this scenario? (2) How can I pass a model object from one controller to another?

I intend to keep it till the user logs out
Then you can use session. But I suggest not saving a lot of information. So for example you have this model or entity:
public class AccountModel {
public int Id {get;set;}
public string Username {get;set;}
// and a whole lot more of properties
}
I suggest you just store an identifier field, either the Id or the Username. Then when another request comes in and you need to either validate the request or update that same model, you can:
Fetch the data again for that user and all relevant information
Update the necessary fields
Save it in your database
So you would do something like:
// to save it in a session after logging in
Session["current_user_id"] = id_variable;
// to retrieve it from session after another request comes in
var id = (int)Session["current_user_id"];
// fetch from your database
// do the necessary update
// persist the changes

(1) How can I achieve this scenario?
You could retrieve the Account model from your datastore when you need to access it.
(2) How can I pass a model object from one controller to another?
See (1). Since you are retrieving it from the data store you don't need to be passing it around.

Related

Phalcon working with MySQL routines

I have a MySQL database which has GUID's stored as binary(16) for the primary keys. I'm using a MySQL user defined routine when inserting and selecting to convert the id's to and from GUID's (GUIDToBinary() and BinaryToGUID()).
In order to use my routines in Phalcon, I am setting the 'columns' parameter for the find() and findFirst() model functions which now means i'm working with incomplete objects as the functions return an instance of Phalcon\Mvc\Model\Row.
The docs state when using the columns parameter the following occurs;
Return specific columns instead of the full columns in the model. When
using this option an incomplete object is returned
UserController.php
// Returns Phalcon\Mvc\Model\Row
$incompleteUser = User::find(['columns' => 'BinaryToGUID(id) as id, status, username, password, .....']);
// Create a new user object to update
$user = new User();
// Populate with existing data
$user->assign($incompleteUser->toArray());
// Assign new changes requested by the user
$user->assign($this->request->getPost());
// Update
$user->updateUser();
User.php
public function updateUser()
{
$manager = $this->getModelsManager();
return $manager->executeQuery("UPDATE User SET ..... WHERE id = GUIDToBinary(".$this->getDI()->get('db')->escapeString($this->id).")");
}
Irrespective of the fact that I've explicitly defined an update, an insert is performed due to the Model being in a transient state.
One solution I thought of was to move the binary to GUID conversion into Phalcon by using Model events however I can't find a suitable method for performing the conversion when selecting. Updating/Inserting is possible by using the beforeSave() and beforeUpdate() events. Perhaps I could just have different properties getId() and getIdGuid() within the model but I would prefer to avoid this if possible.
Is there a way to use MySQL user defined routines in Phalcon and hydrate my model so that it remains in a persistent state? Or do i need to go down the raw SQL route for my updates and avoid PHQL?
Thanks in advance for your time.

Authentication in liferay pages

We are having a portlet on a liferay page. We want to put up up a permission on every action method that is performed. For example on page A we have landed an XYZ portlet. Now we want that whenever there is any action performed form this portlet, we want to check that if the user is having a role to perform this action or not.
It wont be a good approach to put up the code in Action method of the portlet cause we are having approximately 20 such pages and portlets.
Can we have some sort of filter or so, so that each action request is checked if the user is having the access to the content or not.
Thank you...
My idea.
Use a filter to intercept all request
You can add a filter to the Liferay Servlet to check every request.
For that you can use a hook-plugin.
Look at this :
http://www.liferay.com/fr/documentation/liferay-portal/6.1/development/-/ai/other-hooks
http://connect-sam.com/2012/06/creating-servlet-filter-hook-in-liferay-6-1-to-restrict-access-based-on-ip-location/
Issue with filter is that you can't access ThemeDisplay or use PortalUtil.getUser(request).
So you must use work around like that :
private User _getUser(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
User user = PortalUtil.getUser(request);
if (user != null) {
return user;
}
String userIdString = (String) session.getAttribute("j_username");
String password = (String) session.getAttribute("j_password");
if ((userIdString != null) && (password != null)) {
long userId = GetterUtil.getLong(userIdString);
user = UserLocalServiceUtil.getUser(userId);
}
return user;
}
Filtering the request
To filter the request you must get :
page id (Layout id in Liferay)
portlet id
portlet lifecycle
One more time using a filter is a pain because you can get the ThemeDisplay. These params are easy to get (with real object instancee) with ThemeDisplay.
So you must get this as parameter in the request.
final String portletId = ParamUtil.get((HttpServletRequest) servletRequest, "p_p_id", "");
final String layoutId = ParamUtil.get((HttpServletRequest) servletRequest, "plid", "");
final String portletLifecycle = ParamUtil.get((HttpServletRequest) servletRequest, "p_p_lifecycle", "");
Lifecycle details :
portletLifecycle is a int and the meaning of value is :
0 : RENDER
1 : ACTION (the one that interests you)
2 : RESOURCE
I think that with this data you can be able to define if user can or cannot make the action.
You can get user roles from the user.
You can get the current page and portlet linked to the request.
And you can know if the request is an action request.
Good luck with Liferay.
You can add freely configurable permissions to Liferay, see the Developer Guide for detailed information. My first guess on this would be that these affect "model resources", e.g. the data that your portlet is dealing with, rather than portlet-resources, e.g. permissions on the individual portlet itself. Think of portlet-permissions as permissions that are defined by Liferay, model-resources as permissions where you can come up with your own vocabulary on the actions, e.g. "UPDATE_ADDRESS" etc.
These permissions will typically be tied to roles, which are granted to users/usergroups/etc.
Based on this variability, it depends on the nature of your permissions if you can write a filter to generically check permissions, or if it depends on more than the individual action call.
If you determine that there is a generic solution, look up PortletFilters, they behave just like ServletFilters. These can easily provide a home for permission checks.
It's quite hard to cover this topic in such a short answer, I hope to have given enough resources for you to continue your quest.
You can abuse some existing portlet permission like "Add to Page" and set it to roles that should call the action.
And by the rendering and action phases validate "has the user necessary permission".
Or you can create new permission and configure it by portlet-configuration. This way is cleaner, but difficulty.

Titanium access a model from other controller

I learned that is this how to access a model from other controller,
var book = Alloy.Models.instance('book');
And this is how to access a property of a model,
var name = book.get('name');
However in the console,the name logs [INFO] : { } , meaning this doesn't get its property value, and ofcourse the model has already a data saved on it. Thanks for your help!
You may have to fetch the collection first:
var books = Alloy.Collections.book;
books.fetch();
This will load all the models from the collection so you can use them.
although the above works, there are a few addtional points here.
the call is asynchronous in most cases so you should be getting the model in a callback which is not presented in the code above.
I dont know if fetching the collection everytime you want a model is the correct approach either? If the collection already exists you just need to get the model from the collection just using the id.
depending on the exact use case, you might just want to pass the model as a parameter from one controller to the next

Editing User Profile Data in SimpleMembership

I am using SimpleMembership in an MVC4 web app. I can't figure out how to edit the profile information. I thought I could do it just as you do any other table.
[HttpPost]
public ActionResult EditUser(UserProfile user)
{
if (ModelState.IsValid)
{
udb.Entry(user).State = EntityState.Modified;
udb.SaveChanges();
return RedirectToAction("Index");
}
But I get an error saying entity state does not exist in the current context. My context is defined as follows at the top of the controller.
private UsersContext udb = new UsersContext();
I can find plenty of references on access profile data but nothing for editing the data. How can I save the edited UserProfile data back to the db?
EDIT: I was able to resolve the entityState error -- I had to include system.data and system.data.entity. However now when I run I get an error on edit which says unexpected number of rows modified (0). and points to the udb.SaveChanges() line. Still can't figure out how to modify UserProfile data elements.
Simple answer. I needed to set all the fields for the Model in my view. I was only allowing the user to change 4 out of the 6 so two were not being set.
I thought when you pass the model to the view, the view would pass the same field values onto the action if they were not set in the view. For example: if I set FirstName in the view but not UserName the original UserName that was sent to the view would be passed to the Model. That appears not to be the case. For all the items in the model I did not allow them to change in the view I had to set hidden fields to set the fields so a complete model was sent.
It may be better to set individual fields but I am not sure how to do that yet and that was not the question.

LINQ-to-SQL repository pattern attempt that is working, but am concerned with seperation

I am new to LINQ to SQL and the repository pattern and was attempting to do a simple example to get an understanding of how exactly my application should be structured. On my User model object I have a method called create(). When a user is created I want to insert into my User table and insert into my user_role table to assign the user the lowest possible role. I have a method on User model called create which does all this work. Shown below. Am I on the right path with how the repository pattern with LINQ to SQL should work.
public Boolean Create()
{
UserDbDataContext context = new UserDbDataContext();
// Create user.
IUserRepository userRepo = new UserRepository(context);
userRepo.Create(this);
// Get role that user should be added to.
IRoleRepository roleRepo = new RoleRepository(context);
var role = roleRepo.GetByRoleName("rookie");
// Insert user into role.
IUserRoleRepository userRoleRepo = new UserRoleRepository(context);
User_Role userRole = new User_Role();
userRole.RoleId = role.Id;
userRole.UserId = this.Id;
userRoleRepo.Create(userRole);
context.Dispose();
return true;
}
This is my controller method.
public ActionResult Register(string username, string password, string email)
{
User user = new User();
user.Username = username;
user.Password = password;
user.Email = email;
user.DateCreated = DateTime.Now;
user.Create();
return RedirectToAction("Test");
}
Is there a better approach I could take to improve the process? Any help would be vastly appreciated.
One of the main problems in your current approach is that the repositories individually have the responsibility to create/update the entities they hold on the database - This means that if you have changes in one repository and update another repository (i.e. your Create() call) both will be committed to the DB.
The usual way to structure this is having a unit of work (i.e. see here) that sits on top of all repositories that is responsible to commit changes to the DB, this structure also allows for transactions spanning multiple repositories.
I would say you should probably keep the responsibility of the repository to be saving and retrieving data for the entity. The "role" is a bit more on the "business logic" side and I would put that one layer up in a Service so you don't do any business logic responsibilities in the repository. For example you could call it CreateNewUserService and it would take the new users from the repository and then add the role. You would call that directly from the controller passing those arguments that you are applying directly now.
That way if your business logic changes so that you want to intialize the user as something else or not at all, you don't have to rip up the repository as it can keep it's responsibility of providing the user. This keeps the separation of concerns to be more clear as well and helps with maintenance and testability of both the repository and the service.