How to store parameters for action to be used again later - session

I have a list view that can be sorted, searched and filtered. From that list view the user can edit items in multiple steps. Finally after editing and reviewing the changes the user goes back to the list. Now I want the list to use the same sorting, search term and filters that the user set before and show the correct results.
How can multiple paramters (sorting, search, filter) be stored and reused when showing the list action?
Possible unsatisfactory ways that I thought of:
pass through all the needed parameters. Does work hardly if there are multiple actions involved between the two list action calls
save the parameters in the session object. This seems to require a lot of code to handle multiple parameters (check if parameter was passed to action, store new value, if parameter was not passed, get old parameter from session, handle empty string parameters):
Long longParameter
if(params.containsKey('longParameter')) {
longParameter = params.getLong('longParameter')
session.setAttribute('longParameter', longParameter)
} else {
longParameter = session.getAttribute('longParameter') as Long
params['longParameter'] = longParameter
}

If you want to make it more generic you could use an Interceptor instead.
This could perhaps be generalized like this:
class SessionParamInterceptor {
SessionParamInterceptor() {
matchAll() // You could match only controllers that are relevant.
}
static final List<String> sessionParams = ['myParam','otherParam','coolParam']
boolean before() {
sessionParams.each {
// If the request contains param, then set it in session
if (params.containsKey(it)) {
session[it] = params[it]
} else {
// Else, get the value from session (it will be null, if not present)
params[it] = session[it]
}
}
true
}
}
The static sessionParams holds the parameters you want to store/retrieve from session.
If the params contains an element from the list, it is stored in session under the same name. If not, it is taken from session (given that it exists).
In your controller, you can now just access params.getLong('theParam') like you always would. You could also use Grails parameter conversion:
def myAction(Long theParam) {
}
Lots of LOC saved.

I use the session as well. Here is a sample that you may adapt to your needs:
def list() {
if (request.method == 'GET' && !request.queryString) {
if (session[controllerName]) {
// Recall params from memory
params.putAll(session[controllerName])
}
} else {
// Save params to memory and redirect to get clean URL
session[controllerName] = extractParams(params)
redirect(action: actionName)
return
}
// Do your actions here...
}
def extractParams(params) {
def ret = [:]
params.each { entry ->
if (entry.key.startsWith("filter_") || entry.key == "max" || entry.key == "offset" || entry.key == "sort" || entry.key == "order") {
ret[entry.key] = entry.value
}
}
return ret
}

Using session is your best bet. Just save the preference when preferred. I mean, when user sorts, or filter, just save that information in the session, for that particular <controller>.<action>, before returning the page. Next time, check the session, if it has anything related to that <controller>.<action>, apply those; otherwise render the default page.
You might like to use some Interceptor for this, as suggested by sbglasius, here.
I hope you're getting my point.

Related

postsharp - Parameter value based caching

I am using the postsharp cache and I have created a sample function to cache the result of that - but I want to do caching based on parameter values only.
For example, my function looks like this
[Cache(SlidingExpiration = OneHour, IgnoreThisParameter = true )]
public IEnumerable<String> Get(int dateId)
{
// code processing
}
I want the output of this function to be cached if the dateid= T-1 (yesterday) and not when dateid is not T.
But with [Cache] attribute decorated, everything gets cached. Basically I want to cache T-1 data only and not data for any other dates.
This pattern is used so that we can invalidate the caches using custom methods but I dont see any option for selective parameter value based caching.
Can anybody respond to this?
Currently this is not possible. At this moment you need to split method into three methods and have:
public IEnumerable<string> Get(int dateId)
{
if (dateId == CurrentDate - 1)
GetCached(dateId);
else
GetCore(dateId);
}
[Cache(SlidingExpiration = OneHour, IgnoreThisParameter = true )]
private IEnumerable<string> GetCached(int dateId)
{
return GetCore(dateId);
}
private IEnumerable<string> GetCore(int dateId)
{
// ...
}
This is in the backlog, but it is not scheduled to any release at the moment.

How to use http patch request in spring boot?

I am trying to use PATCH request.
below is the code which i am using. and it is like ladder of if statements
#PatchMapping("/updateInvoiceByEmail/{email}")
public Mono<ResponseEntity<Invoice>> updateInvoiceByEmail(
#PathVariable String email,
#RequestBody Invoice invoice) {
return invoiceRepository
.findByEmail(vendorEmail)
.flatMap(existing -> {
if (invoice.getInvoiceStatus() != null) {
existing.setInvoiceStatus(invoice.getInvoiceStatus());
}
if (invoice.getCanRaise() != null) {
existing.setCanRaise(invoice.getCanRaise());
}
if (invoice.getAttachmentId() != null) {
existing.setAttachmentId(invoice.getAttachmentId());
}
if (invoice.getInvoiceId() != null) {
existing.setInvoiceId(invoice.getInvoiceId());
}
... and so on.
return invoiceRepository.save(existing);
})
.map(updatedInvoice -> new ResponseEntity<>(updatedInvoice, HttpStatus.OK))
.defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
I am using
Spring WebFlux and mongodb
How can i make shorter and cleaner.
Thanks
You can use reflection if you want to reduce number of lines although reflection is always last thing that you should do. What I would do is to move this if - get - set logic in separate component(in separate class or method). Aside from that, I would just like to mention that simplicity is not the only problem here. Assume that null is valid value sent by client, you will need some mechanism how to detect if value is not sent or you explicitly wanted to set null value. Some example of moving this code to separate component would look something like this:
class InvoiceAssembler {
public static assemble(Invoice existing, Invoice newInvoice) {
if(newInvoice.getInvoiceId() != null) {
existing.setInvoiceId(newInvoice.getInvoiceId());
}
...
}
}
Only way I see you could improve is if you use a UpdateDTO for the fields that are most likely to be updated and therefor reduce the amount of fields you have to check.
Good description of how you use UpdateDTO here
Otherwise you are left with reflection but I don't know if that would make your code more readable or more confusing instead.

To create a session explicitly for first the first time page loads in Grails

As soon as a page loads, it renders a lot of data and shows on the view which sort of slows down the performance. I want to restrict this and load the data only when a filter is applied .
I need a way in which a session variable can store the value on the 1st login and no data should be loaded in that 1st session i.e. when any user loads it for the very first time using his login. something like the below in the controller class:
if(session.dtstartDate && session.dtstartDate != '')
{
SimpleDateFormat nsdf = new SimpleDateFormat('yyyy-MM-dd')
Date startDateValue = nsdf.parse(session.dtstartDate.substring(0, session.dtstartDate.lastIndexOf("T")))
eq("startDate", startDateValue)//if any filter is applied
}
else{
if this is the 1st session the startdate should be null --> need a piece of code to be replaced here
}
I am unsure maybe I still have not got what you have tried to ask properly, I thought I should try to answer your question to how I understood your problem to be.
If we take this basic filter and add some stuff to it we may be able to get to what you wish to do using a better method ? I am unsure what startDate is actually representing but if we base it on if a user has hit a controller for the first time or not the answer would be something like this, you could replace the logic to startDate if it has other significance:
so adding some hashmap arrayset to your filter that gets called before the action is called when user clicks the controller/action:
in your conf/MyFiters.groovy
class MyFilters {
static final Set<HashMap<String[],String[]>> userControl =
([:] as Set).asSynchronized()
//where controller is controllerName and action is actionName
def filters = {
MyLogger() {
before = {
if (verifyClientMaster(session.id as String ,controllerName)==false) {
clientMaster.add(session.id as String:controllerName)
// now here you have a new user so set
// some session value for gsp or load something
//according
}else{
// user has hit it before do something else or set something else
}
}
}
}
}
Boolean verifyClientMaster(String sessionId,String controller) {
// iterate
boolean found = false
userControl.each { k,v -> if (k == sessionId && v == controller) {
found = true
}
}
}
something like this and you know if the user has hit the controller or not.. remember the session is per user. so a new user has a new session entity.
Hope it is of help and not off track..
E2A
Thinking about it you do go down this route then you would need to keep track of when session expires and to remove the user from clientMaster.. take a look at this project if you did go down this route.. personally I would even do it simpler than this... on a rethink...
class MyFilters {
def filters = {
MyLogger() {
before = {
if (!sessions."${controllerName}") {
sessions."${controllerName}"="${controllerName}"
// now here you have a new user so set
// some session value for gsp or load something
//according
}else{
// user has hit it before do something else or set something else
}
}
}
}
}
and even simple than any of this would be to use the intelligence built into a gsp if what you load can be based on it... (not tested any of it ha)
<g:if test="${!session."${controllerName}"}">
<g:set var="${controllerName}" value="${controllerName}" scope="session" />
<g:render template="firstTimeHitter"/>
</g:if>
<g:else>
<g:render template="secondTimeHitter"/>
</g:else>
or just your controller that checks and sets that and either renders something different or sets something gsp picks up on..
def myController {
def doSomething() {
boolean firstTime = false
if (!session."${controllerName}") {
// first time either render or set firsTime
firstTime = true
session."${controllerName}" = controllerName // or startDate
// render view: 'firstTime, model: [firstTime:firstTime, params:params]
} else{
// render view: 'firstTime, model: [firstTime:firstTime, params:params]
}
// if no render above:
render view: 'doSomething, model: [firstTime:firstTime, params:params]
// now in doSomething gsp you look for firstTime:
}
do someThing:
<g:if test="${firstTime.toString().equals('true')}">
<g:render template="firstTimeHitter"/>
</g:if>
<g:else>
<g:render template="secondTimeHitter"/>
</g:else>
The possibilities are endless, the differences being with a filter its a one fits all, i.e. it is checking every controller as it is hit by each user. In controller and gsp solution you have to declare it where needed. You could have an abstract controller that other controllers extend to repeat that check as a higher class that gets called to verify, regardless their all a lot more repetitive than a simple one off filter...
Final Edit to give other other alternatives would be:
final Set<Session> jsessions = ([] as Set).asSynchronized()
jsessions.add('controller1')
jsessions.add('controller2')
jsessions.add('controller3')
jsessions.add(controllerName)
println "=== ${jsessions}"
if (jsessions.contains(controllerName)) {
println "--- We have ${controllerName} defined in our session set.... jsessions"
}
ArrayList jsessions2 = []
jsessions2.add(controllerName)
session.jsessions2 = jsessions2
//repeat this on every call
ArrayList jsessionsret = session.jsessions2
jsessionsret.add('controller1')
jsessionsret.add('controller2')
jsessionsret.add('controller3')
session.jsessions2 = jsessionsret
if (jsessions2.contains(controllerName)) {
println "--- We have ${controllerName} defined in our session set.... jsessionsret"
}
println "222 --- ${jsessions2}"
This segment above are two different implementations of using first a session set that is global and could be used if you do not care if the controller is hit by usera userb etc so if usera hits it userb would also be considered as hitting it.. This is jsessions.
The bottom jsessions2 is an attempt to turn a single session key into an ArrayList. So rather than storing lots of single object i.e. session."${controllerName}" per call of a controller per user session. You could have 1 single session key per user that you append each controller they hit to.. and you then check to see if they have that controller

Users restrictions for associated data in ASP Membership

I have a site I'm porting to MVC to clean up the code and simplify things. I use the asp membership and profile providers, but I'm wondering if I'm doing this correctly for my situtation. I'm pretty new to MVC, so I wan to get this right in the early stages.
Users are individuals and they are part of larger "institutions" that they either set up or pick at registration. In this case, the institution is a winery. I want the users to be able to view all wines from every winery, but only edit ones that belong to them.
What's the best way to do this? Right now I render the link to the edit field in my index view based on their instution ID and the producer ID. I feel like a data annotation might work better here, but I don't exactly how to implement that for a group of wines. Do I need multiple providers? I use roles to limit the editing, but right now an editor role could manually enter the path of another wine to edit it when that wine doesn't belong to them.
Any pointers here would be awesome. I know I can do it in the controller methods, but I'm looking for the 'right' way to do it. Thanks.
I'm running into the same issue at work right now, and the best proposed solution we have right now is implementing an "ownership" table. You won't be able to solve this using roles.
So basically you have an owner ID, owned object's ID, and the type of objects ID all held together. Lets take an edit request for example. We know that you can only edit the data person X owns, so we have a stored procedure that if a key combination exists in our ownership table where person.ID = owner ID, and item.ID = object ID, and item.TypeID = objectTypeID. If it exists, it goes along performing its edits, otherwise it returns an error.
You can use this scheme to return ownership lists, user validation, and a host of other issues you may come across. You probably won't need the ObjectTypeID if you only have one type's ownership being tracked. Hope this helps!
I figured this out by applying a custom AuthorizeAttribute to the edit, delete, and create actions.
Here is what I ended up doing:
public class ProducerEditAttribute : AuthorizeAttribute
{
private vfContext db = new vfContext();
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
bool bAdmin = filterContext.HttpContext.User.IsInRole("admin");
bool bProdEdit = filterContext.HttpContext.User.IsInRole("producereditor");
bool bProd = filterContext.HttpContext.User.IsInRole("producer");
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (bAdmin)
{
//authorized
}
if (bProdEdit || bProd)
{
//check for current wine belonging to the producer.
Producer currentProd = db.Producers.Find(Profile.GetProfile(filterContext.HttpContext.User.Identity.Name).InstitutionID);
Wine currentWine;
object WineID;
if (filterContext.RouteData.Values.TryGetValue("id", out WineID))
{
currentWine = db.Wines.Find(int.Parse(WineID.ToString()));
if (currentProd.Wines.Contains(currentWine) && bProdEdit)
{
//authorized
}
else if (bProd)
{
var result = new ViewResult();
result.ViewName = "Login.cshtml"; //this can be a property you don't have to hard code it
result.MasterName = "_Layout.cshtml"; //this can also be a property
result.ViewBag.Message = "You do not have permission for add/edit/delete funciontionality. Please request.";
filterContext.Result = result;
}
else
{
var result = new ViewResult();
result.ViewName = "Login.cshtml";
result.MasterName = "_Layout.cshtml";
filterContext.Result = result;
}
}
}
else
{
var result = new ViewResult();
result.ViewName = "Login.cshtml";
result.MasterName = "_Layout.cshtml";
}
}
}
}

How can I create temporary records of Linq-To-Sql types without causing duplicate key problems?

I have code that generates records based on my DataGridView. These records are temporary because some of them already exist in the database.
Crop_Variety v = new Crop_Variety();
v.Type_ID = currentCropType.Type_ID;
v.Variety_ID = r.Cells[0].Value.ToString();
v.Description = r.Cells[1].Value.ToString();
v.Crop = currentCrop;
v.Crop_ID = currentCrop.Crop_ID;
Unfortunately in this little bit of code, because I say that v.Crop = currentCrop,
now currentCrop.Crop_Varieties includes this temporary record. And when I go to insert the records of this grid that are new, they have a reference to the same Crop record, and therefore these temporary records that do already exist in the database show up twice causing duplicate key errors when I submit.
I have a whole system for detecting what records need to be added and what need to be deleted based on what the user has done, but its getting gummed up by this relentless tracking of references.
Is there a way I can stop Linq-To-Sql from automatically adding these temporary records to its table collections?
I would suggest revisiting the code that populates DataGridView (grid) with records.
And then revisit the code that operates on items from a GridView, keeping in mind that you can grab bound item from a grid row using the following code:
public object GridSelectedItem
{
get
{
try
{
if (_grid == null || _grid.SelectedCells.Count < 1) return null;
DataGridViewCell cell = _grid.SelectedCells[0];
DataGridViewRow row = _grid.Rows[cell.RowIndex];
if (row.DataBoundItem == null) return null;
return row.DataBoundItem;
}
catch { }
return null;
}
}
It is also hard to understand the nature of Crop_Variety code that you have posted. As the Crop_Variety seems to be a subclass of Crop. This leads to problems when the Crop is not yet bound to database and potentially lead to problems when you're adding Crop_Variety to the context.
For this type of Form application I normally have List _dataList inside form class, then the main grid is bound to that list, through ObjectBindingList or another way. That way _dataList holds all data that needs to be persisted when needed (user clicked save).
When you assign an entity object reference you are creating a link between the two objects. Here you are doing that:
v.Crop = currentCrop;
There is only one way to avoid this: Modify the generated code or generate/write your own. I would never do this.
I think you will be better off by writing a custom DTO class instead of reusing the generated entities. I have done both approaches and I like the latter one far better.
Edit: Here is some sample generated code:
[global::System.Data.Linq.Mapping.AssociationAttribute(Name="RssFeed_RssFeedItem", Storage="_RssFeed", ThisKey="RssFeedID", OtherKey="ID", IsForeignKey=true, DeleteOnNull=true, DeleteRule="CASCADE")]
public RssFeed RssFeed
{
get
{
return this._RssFeed.Entity;
}
set
{
RssFeed previousValue = this._RssFeed.Entity;
if (((previousValue != value)
|| (this._RssFeed.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._RssFeed.Entity = null;
previousValue.RssFeedItems.Remove(this);
}
this._RssFeed.Entity = value;
if ((value != null))
{
value.RssFeedItems.Add(this);
this._RssFeedID = value.ID;
}
else
{
this._RssFeedID = default(int);
}
this.SendPropertyChanged("RssFeed");
}
}
}
As you can see the generated code is establishing the link by saying "value.RssFeedItems.Add(this);".
In case you have many entities for wich you would need many DTOs you could code-generate the DTO classes by using reflection.

Resources