Do not change the router values ​in the address - html

I have a page (index) with an #ActionLink that opens another page to edit an invoice, the page will appear correctly, but the [Url-address] shows the number for the invoice, and when I change the number for the invoice in the [Url-address], it means that he opened another invoice, and I want the modification page not to open from By modifying the [Url-address] or using a direct link, I found a nice way, but it is used with [Post] and not Get. Is there a way to protect the [Url-address] of the page from being modified and its values?
View Index:
#Html.ActionLink(
linkText: "Edit_Invoice",
actionName: "Invoice_Edit",
controllerName: "Invoice",
routeValues: new { ID_Invoice = 2 },
htmlAttributes: new { area = "Pro"})
Controller :
[HttpGet]
public ActionResult Invoice_Edit(int id_invoice)
{
Table.Invoice invoice = (from i in Cn.Invoice
where i.ID_Invoice == id_invoice
select i).FirstOrDefault();
return View(invoice;
}
View Invoice_Edit:
#Html.TextBoxFor(m => m.ID_Invoice)
#Html.TextBoxFor(m => m.Date_Invoice)
<button>save</button>
When you open the invoice modification page, its number will appear in the address as in the link below
https://localhost:44320/Pro/Invoice/Invoice_Edit?ID_Invoice=2
I only want to open invoices that are selected from the page only.
Update 1 : Change Title Answer

if you what users to open only invoices that they are allowed to open, antiforgery token has nothing to do with it. You neeed server side validation, authentication and authorization. All of these should be implemented on the server side. Client side javascript code is not enough.
Anti-Forgery Tokens don't make a lot of sense for any request where you're not modifying and persisting data. So I recommend to remove [ValidateAntiForgeryToken] from your GET since GET request will be returned to the user, not the attacker.
AntiForgeryToken is designed for POST requests and it expects the token in Request.Form collection. You can just use post instead of get to receive data. Or you can use ajax. Google and you will find some examples.
But make sure that you are using them when you're creating, updating or deleting data.

Related

Telegram api. Get all uploaded photos by media_group_id

I send to my telegram bot a few photos as group. How I can get the file_id all of my uploaded photos?
I use webhooks, but response is not contain any data about all photos, just some data about last uploaded photo and media_group_id. How I can get all file_id's of my uploaded group photos
response:
The Telegram Bot API does not give to your web-hook any reliable information about the order of each item in a media group. https://core.telegram.org/bots/api#message
Suggestions:
If bot is in a private chat, save the incoming file_id against their media_group_id. Whenever media_group_id changes you would have all you need to use. Engage the user in some other way so that you can quickly determine the media_group_id change and respond quickly from that processing.
If bot is in a group chat, save incoming file_id against the users id as well as media_group_id and similarly monitor changes to media_group_id and user id to take action.
When a solution starts getting too complex for my liking, I prefer to go back to the basic reason for my need and perhaps find out that I do not need to do something an API doesn't afford like "Get all uploaded photos by media_group_id". Maybe I can just process them individually as the updates stream in.
Tip: If the media group has a caption and you only care about the first media item in the group, then monitoring the media_group_id and caption of an incoming message should be sufficient.
if(message.caption != null && message.media_group_id != null){
// first item in new group received
}
Okay, this way is not simple and not elegant but it's working.
We need to see in webhook response media_group_id element - this means that this is a group of media.
If the first point is true - save the data about this media on own server (data must be contain media_group_id)
example: ["media_group_id" => [[some data about photo]]]
When next webhook is come, we need to see his media_group_id, if it's the same - ok, add him to array...
example: ["media_group_id" => [[some data about photo],[some data about photo]]]
if not - ok, make a new element of array:
example: ["media_group_id" => [[some data about photo]], "media_group_id2" =>
[[some data about photo]]]
So we got an array that contains all data about the photos of the one(or more) group.
hmmm... I don't like this way, but how make better?
In Pyrogram, we can use the get_media_group function, https://docs.pyrogram.org/api/methods/get_media_group.html#pyrogram.Client.get_media_group. in my opinion, it is much better than using BOT API.

Passing Model sub-tables to HTTPPOST Controller for Model Editing

I have created a MVC 5 application where I am creating a custom purchasing system.
My View model is generated based on the contents of an SQL Database. The database uses a Single Primary Key for a Purchase Order with some basic data. In addition to the basic data each PO can have multiple items within that purchase order. This creates a relationship where there can be N items to a single Purchase.
When I am doing a form Submit the sending of the Purchase Order specific information, ie using TextBoxFor(m => m.Date), works fine. However I cannot seem to pass the list of all the Items within it. For example when I am doing #Html.TextBoxFor(m => m.Details.ItemName) it is not populating the section in the model during the POST.
I have tried sending all the information using #Html.TextBoxFor(m => m.Details) but it throws errors as the TextBoxFor cannot handle these data types.
I am after a system where I can edit a purchase order model by adding or removing items without committing to my database until the 'save' button is pressed.
My View Model example is
public class PurchasingEditModel
{
public tbl_PurchaseOrder PurchaseOrder;
}
Purchase order in itself has a link to PurchaseOrderDetails (within SQL) via a Foreign key reference of the Purchase Order. This creates the Many Items to One PO.
The controller for the edit page is
public ActionResult Edit(int? pkPurchaseOrder)
{
model.PurchaseOrder = db.PurchaseOrder.Where(x => x.pkPurchaseOrder == pkPurchaseOrder);
return View(model);
}
This together with a standard Edit.cshtml using #Html.TextBoxFor(m => m. all works fine with the display portion, until I want to post the multiple items within the sub-table.
Really the easiest way for me to handle this would be to pass the all contents of model during the display, which has all the elements of the items within the PO, to the POST function.
Any guidance you can give is appreciated.
I have solved my own issue, which makes a change...
To POST the data within a sub-table(IQueryable) Ive had to do the following
Within my main html code add
#foreach(var item in Model.PurchaseOrder.tbl_Details)
{
#Html.Partial("_POItemDetailsPartial", item)
}
Then Ive had to create a MVC Partial Page (Razor) named _POItemsPartial.
Within that page I have put the following..
#using (Html.BeginCollectionItem("Model.PurcahseOrder.tbl_Details")
{
#model ModelSpace.Model.tbl_Details
#Html.TextBoxFor(m => m.Description)
}
When the POST action occurs I now get the description for all the 3 items I have within the PurchaseOrder.
**
UPDATE:
**
Despite getting this data..I am now losing all my original model data such as Total Price it seems that the Partial Call being passed the Model.tbl_Details is only passing that information and clearing the rest.
When it returns it ends up with all higher level data removed. If I comment out the partial call it all comes back.
Turns out I still need help.... :(

"Create or update" form behavior when hitting back button

I have the following workflow on a website:
Some user John Doe declares a company through form 1
(fields: name, head office location)
After John Doe submits (HTTP POST) form 1, he is redirected (HTTP 302) to company form 2 with additional legal information about the company.
The problem is, if John Doe hits the back button of his browser during step 2, he will land on the form 1, with data filled by the browser (using values he already submitted — that's what Firefox and major browsers seem to do).
John Doe might then think he can use this form to update some information (e.g. fix a typo in the name of the company) whereas he will actually create a new company doing so, as we don't know on the server side whether he wants to declare a new company or update the one he just created.
Do you know any simple solution to handle that problem ?
Use javascript/jquery script after the page is loaded to empty all the inputs. This will prevent confusion of "updating the company".
jQuery would look something like this:
$('#elementID').val('');
You can also handle the situation by manipulating the browser history
on load of form 2, and pass the CompanyId generated on submit of form 1 using querystring. So that you can actually update the company as the user
Suppose John submits form1.html, a unique CompanyId "1001" is generated and redirected to form2.html. Now on load of form2 you can modify the browser history form1.html?companyid=1001 using
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 1", "form1.html?companyid=1001");
Now, when the user click back button and submits the form1 again. you can check for companyid in querystring and update the company.
I think it is more user-friendly when user can return back to previous form and update it (instead preventing the described behavior).
I use in most cases similar way to handle described problem:
Let's assume that user is on the page /some-page, that contains "Create new company" button.
When the user opens this page, will be executed special method createOrFindCompanyDraft() on the server-side. This method creates new company "draft" record in DB (only for the current user). For example, draft record has primary key id=473. When you execute this method again it will return the same record with the id=473 (with "draft" status). "Draft" record should't display on any other interfaces.
And "Create new company" has link /company/common/473.
When user go to /company/common/473, you display form 1, that will be filled from "draft" record. At first time user will see empty form.
Technically user will update the existing record, but you can display "Create new company" title on the page.
Then user go to form 2, for example, /company/legal-info/473, you create similar draft record for the this form (similar to step 1).
When user submit the form 2, you will remove "draft" status from the record id=473 (and any related records).
Next time when user open page /some-page, will be created new draft record for the current user.
Browser history will contain:
/some-page
/company/common/473
/company/legal-info/473
/some-page2
I like this approach, because all form only update records. You can go to previous/next form many times (for example "Back"/"Forward" browser buttons). You can close browser, and open not completed forms tomorrow. This way doesn't require any additional manipulation with the browser history.
try this
<form autocomplete="off" ...></form>
And Another
Use temporary tables or session to store the Page 1 form data. If the page 2 form is submitted use the temporary data of page 1 which is stored in database or in session.
Use a Separate key (Hidden field ) in both page 1 and page 2.
Actually I thought of a trick to obtain that "create on first post, update after" behavior (just like the user thinks it should behave).
Let's say the step 1 form is at the URL /create_company/. Then I could have that page generate a random code XXX and redirect to /create_company/?token=XXX. When I create the company I save the information that it was created through page with token XXX (for instance, I save it in user's session as we don't need to keep that information forever) and when the form is submitted, if I know that a company was already generated using this token, I know the user used the same form instance and must have used the back button since the token would be different if he explicitly asked for another company.
What do you think ? (I initially thought there should be a simpler solution, as this seems a little bit over-engineered for such a simple issue)
This is more like a UX question.
I'd think that the solution lies within the information given to the user on that form, to help them understand what they're doing.
Set a title that says 'Create a company', for example, and set your submit button as 'Create Company' will help your user with that. Use a unique id when you create the company object, and pass the id back to the same URL in order to perform an update. You should then update your title and button that tells user that they are updating instead of creating.
In that sense I'd say it's better to use a more generic URL like /company and /company?id=12345.
You could also consider using Restful API protocol to help your server identifies the CRUD operation. http://www.restapitutorial.com/lessons/httpmethods.html
Without the "routing" part of django it is hard to help. I can just answer my experience from the express.js-router functionality:
you can specify a post on /company, which is for new users.
you can specify another route for post on /company/:companyid for a changing form
and as a response from the create-post you can redirect to the different location.

Yii2 redirect to previous page

Now My application is using gridview to list all information and it's also have pagination.when the user click on pagination number and then click on edit and then save. It redirect user to view page. What I want to do it to redirect user to previous page(url with pagination number).
You could use Yii::$app->request->referrer which returns the last page the user was on.
Usage is straightforward:
return $this->redirect(Yii::$app->request->referrer);
You need also take into account that referrer can be null:
return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl);
See the docs.
Here it says that it's a good practice to check if referrer is set at the first place.
So if you use the following code you will be redirected to last page if referrer is set or to your configured homeUrl if the return URL was not set previously.
return $this->goBack((!empty(Yii::$app->request->referrer) ? Yii::$app->request->referrer : null));
goBack() details
redirect details
It is true what #Kostas says, but I think it would be better if you simply code the following, because goBack take account of a null parameter already to goBack HOME.
return $this->goBack(Yii::$app->request->referrer);
I tested it and it works fine.
If you use Html::submitButton when you are in a form and you want to be redirected to the previous page, so mostly to your module list I recommend using use yii\helpers\Url;:
return $this->redirect(Url::previous('previous') ?: ['list']);
because
return $this->redirect(Yii::$app->request->referrer);
will return you back to the form instead of a module list.

Laravel Eloquent how to limit access to logged in user only

I have a small app where users create things that are assigned to them.
There are multiple users but all the things are in the same table.
I show the things belonging to a user by retrieving all the things with that user's id but nothing would prevent a user to see another user's things by manually typing the thing's ID in the URL.
Also when a user wants to create a new thing, I have a validation rule set to unique but obviously if someone else has a thing with the same name, that's not going to work.
Is there a way in my Eloquent Model to specify that all interactions should only be allowed for things belonging to the logged in user?
This would mean that when a user tries to go to /thing/edit and that he doesn't own that thing he would get an error message.
The best way to do this would be to check that a "thing" belongs to a user in the controller for the "thing".
For example, in the controller, you could do this:
// Assumes that the controller receives $thing_id from the route.
$thing = Things::find($thing_id); // Or how ever you retrieve the requested thing.
// Assumes that you have a 'user_id' column in your "things" table.
if( $thing->user_id == Auth::user()->id ) {
//Thing belongs to the user, display thing.
} else {
// Thing does not belong to the current user, display error.
}
The same could also be accomplished using relational tables.
// Get the thing based on current user, and a thing id
// from somewhere, possibly passed through route.
// This assumes that the controller receives $thing_id from the route.
$thing = Users::find(Auth::user()->id)->things()->where('id', '=', $thing_id)->first();
if( $thing ) {
// Display Thing
} else {
// Display access denied error.
}
The 3rd Option:
// Same as the second option, but with firstOrFail().
$thing = Users::find(Auth::user()->id)->things()->where('id', '=', $thing_id)->firstOrFail();
// No if statement is needed, as the app will throw a 404 error
// (or exception if errors are on)
Correct me if I am wrong, I am still a novice with laravel myself. But I believe this is what you are looking to do. I can't help all that much more without seeing the code for your "thing", the "thing" route, or the "thing" controller or how your "thing" model is setup using eloquent (if you use eloquent).
I think the functionality you're looking for can be achieved using Authority (this package is based off of the rails CanCan gem by Ryan Bates): https://github.com/machuga/authority-l4.
First, you'll need to define your authority rules (see the examples in the docs) and then you can add filters to specific routes that have an id in them (edit, show, destroy) and inside the filter you can check your authority permissions to determine if the current user should be able to access the resource in question.