I'm trying to write a Plugin for Trac.
I've succeeded to export variables contents from my request (process_request)
to my template ...but I still having problems doing it in the other way : how to catch the information taped by the user ?
<form name="input" action="" method="POST">
Configuration : <input type="text" name="configuration" value ="$my_var" /> <br /><br />
<label for="file">URL:</label>
<input type="text" name="file" id="WillPosted" value="This text will be changed by the user"/>
<input type="submit" name="SubmiT" value="Browse" /><br /><br />
So how can I catch the content of the input form with the id="WillPosted" ?
Notice : actual problem is in IRequestHandler methods from Trac !
Any Idea ?
Thanks
You're asking about the common web-UI interaction
my_var --> template with input field 'file' and default value 'This will ..'
user input to field
submission by POST request
How to get (changed) new value of input, right? If so, you explained it rather complicated.
And I'm wondering, if you don't know about trac-hacks.org, probably the most authoritative source of Trac plugin code on the planet - much more working examples to look at than needed here.
Anyway, the key is reading the return value(s) from reg.args dict like so:
from pkg_resources import resource_filename
from trac.web.chrome import ITemplateProvider, add_stylesheet
implements(IRequestHandler, ITemplateProvider)
# IRequestHandler methods
def match_request(self, req):
# Any condition evaluating to True will fire the second method.
return req.path_info == '/<your_path>'
def process_request(self, req):
"Demo how to interact with your template."
# Check, if you'r really processing the right request by target matching,
# and only act on input of authorized users - as an added suggestion/option.
if req.path_info.startswith('/<your_path>') and req.authname != 'anonymous':
# Check for request type.
if req.method == 'POST':
# Ok, go pock for the new value now.
value = req.args.get('file', 'default_value')))
# Now go, process it, store it, even redirect away, if you're done.
# Fallback for Trac 0.11 compatibility included.
referer = req.args.get('referer') or req.get_header('Referer')
# Steer clear of requests going nowhere or loop to self
if referer is None or \
referer.startswith(str(req.abs_href()) + '/<your_path>'):
referer = req.abs_href()
req.redirect(referer)
# Still there, so that's the initial call or anonymous user, hey?
# So let's prepare information for displaying the template ...
data = dict(my_var='any_string_or_number')
# Take the env obj from self, if needed.
env = self.env
mod = MyOwnSecondaryModule(env)
if mod.can_do_something:
data['my_var'] = mod.do('better')
# Why not apply an own style?
add_stylesheet(req, 'your_plugin/most_famous_style.css')
return 'your_template.html', data
# ITemplateProvider methods
def get_htdocs_dirs(self):
"""Return the absolute path of a directory containing additional
static resources (such as images, style sheets, etc).
"""
return [('your_plugin', resource_filename('your_plugin_pkg_base_dir', 'htdocs'))]
def get_templates_dirs(self):
"""Return the absolute path of the directory containing the provided
Genshi templates.
"""
return [resource_filename('your_plugin_pkg_base_dir', 'templates')]
Questions on using various Trac extension point interfaces? See the authoritative wiki documentation on the subject as well!
Related
i'm running locally a python file. when i access 127.0.01:5000/string i get to a specific html page. Up to now, using javascript, i managed to put some checkbox (boolean form) on that page, but how can i assign the value of each one of them (True or False) to a variable in the python file?
i'm being unable to use the user's response in anyway.
i'm using flask-ext-wtforms, render_template, etc.
this is what i have on the html file so far.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
var creature=0
var artifact=0
function suggest(){
if ($('#Creature').is(':checked')){creature=1;}
if ($('#Artifact').is(':checked')){artifact=1;}
}
</script>
<input type="checkbox" id = "Creature">Creature<br>
<input type="checkbox" id = "Artifact">Artifact<br>
<input type="checkbox" id = "Enchantment"> Enchantment<br>
<input type="checkbox" id = "Sorcery"> Sorcery<br>
<button type="button" onclick = "suggest(); alert('creature ' + creature + ' artifact ' + artifact)">Submit</button>
It tells me whether or not the user has clicked one of the first two boxes, but that's it. i don't know how to make the python file access such information.
It'd be useful to see what you have in the actual Python file, but I'll give it a go. Also I'll state right off the bat that for these sorts of questions the documentation should be your best friend and first go-to, but here's a start.
From the html you've posted it doesn't look like you're actually using a Flask-WTF Form instance. You would want to first create a Form with BooleanFields like so:
from flask.ext.wtf import Form
from wtforms import BooleanField
class MyForm(Form):
creature = BooleanField()
# etc
submit = SubmitField()
then in your template render the form & the fields like so:
<form method="POST" action="/string">
{{ form.creature.label }}
{{ form.creature() }}
{# ... etc ... #}
{{ form.submit() }}
</form>
Then finally in your view, you have to (A) specify that the view accepts POST requests, (B) create the form, and (C) make sure you pass the form to the template for rendering. If you do all these things, then when you, or someone else, or a robot or whatever click submit, then the browser will POST the data from the form to the flask view, and you will be able to access it in the view as, say, form.creature.data. Example:
#route('/string', methods=['GET', 'POST']) # part A
def get_critters():
form = MyForm() # part B
if form.validate_on_submit():
# do something with form.creature, or form.whatever
return render_template("string.html", form=form) # part C
All of this is very ably covered in multiple parts of each project's documentation. See:
https://flask-wtf.readthedocs.org/en/latest/quickstart.html
https://wtforms.readthedocs.org/en/latest/fields.html#wtforms.fields.BooleanField
and virtually everything at http://flask.pocoo.org/docs/0.10/ but especially http://flask.pocoo.org/docs/0.10/patterns/wtforms/ and http://flask.pocoo.org/docs/0.10/tutorial/.
I'm trying to fill, submit, and test a web form in Play Framework, using ScalaTest and FluentLenium. It seems like it should be very straightforward, but I'm having all kinds of problems.
First, part of the web form in question:
<form class="signin" id="loginform" method="POST" action="/login">
<div class="form-group">
<label for="name">Email Address:</label>
<input type="email" class="form-control" placeholder="Enter Email Address" id="email" name="email" required />
...
This works fine from a real web browser. Now the problem comes when I try to fill in and submit the form:
#RunWith(classOf[JUnitRunner])
#SharedDriver(deleteCookies = false)
#SharedDriver(`type` = SharedDriver.SharedType.PER_CLASS)
class TestWebsiteAuthentication extends Specification {
"Application" should {
"login as an administrative user on the web site" in new WithBrowser with GPAuthenticationTestUtility {
browser.goTo(loginURL)
browser.fill("#email").`with`(prerequisiteAccounts.head.userIdentity) must equalTo(OK)
...
At that last line, I get an exception:
[info] x login as an administrative user on the web site
[error] 'org.fluentlenium.core.action.FillConstructor#1c25c183' is not equal to '200' (TestWebsiteAuthentication.scala:93)
[error] Expected: 200
[error] Actual: org.fluentlenium.core.action.FillConstructor#1c25c183
Any ideas what I'm doing wrong here?
I've tried taking out the "must equalTo(OK)" but this just causes the form to fail on submit -- unfortunately, I haven't been able to find ANY documentation on how to do this, so I'm basically piecing it together bit by bit. Pointers to relevant documentation would be appreciated -- there doesn't seem to be anything complete at Tyrpesafe... just "teasers" that get you started, but no depth. :-(
When you write browser.fill("#email").``with``("x#y.com"), all you're really doing is telling Fluentlenium to edit the template to add a value attribute inside the input tag.
On the other hand, OK is an HTTP status code, so comparing them will naturally yield false.
When you say you tried to submit the form and it failed, i am assuming you did something such as:
browser.fill("#email").`with`("x#y.com")
browser.fill("#password").`with`("myPass")
browser.click("#button") // this should submit the form and load the page after login
and then tried to make an assertion such as:
browser.title() must equalTo("next page") // fails because "next page" != "login page"
one suggestion is to try something like this, Before browser.click:
browser.pageSource() must contain("xyz") // this will fail
When the above assertion fails, it will print the content of browser.pageSource() to your terminal, and you'll be able to see the modifications the Fill function did to the HTML.
In my case, I observed that my pageSource() now contained the following:
<input type="text" id="email" name="email" value="x#y.com"/>
<input type="password" id="password" name="password"/>
Notice how the first input has a value="x#y.com", but the second input is still empty. It turns out the second one is empty because it is an input of type password, however I eventually made the form login work.
Here is a list of things you can look into:
have a database enabled in that Spec
have it populated with Users (in case your form validation connects to a DB, that is)
from what I have experienced, using browser.goTo more than once in a test will not work well with form submission (anyone can confirm?)
Hope this helps
I am somewhat of a novice with CGI Perl and am working on a web app that uses 'mode' and 'action' variables to determine which pages load.
$mode = param('mode');
$action = param('action');
if ($mode eq 'page1') {
if ($action 'eq') {
&performAction;
}
displayPage1;
}
elsif ($mode eq 'page2') {
&displayPage2
}
During development I have been having trouble figuring out the best way to set these variables when trying to navigate to different modes/actions after a form submit.
In some cases, putting a hidden value in the form will work
hidden(-name=>'action',-value=>'save')
but sometimes it will not. In case of the latter, putting param('action',"save") before the form will make the action change when the form is submitted.
I am unable to figure out why this happens though, are there factors that affect these two variables that I am unaware of?
What I now need to do is have two buttons on the same form, one which will just set the action to save the form data, and another which will save the form data but navigate to another mode/page with that form data.
If anyone could at least point me in the right direction for what I should be researching I would be greatly appreciative.
By default the CGI module implements a state-preserving behavior called "sticky" fields. The way this works is that if you are regenerating a form, the methods that generate the form field values will interrogate param() to see if similarly-named parameters are present in the query string. If they find a like-named parameter, they will use it to set their default values.
You want
hidden(-name=>'action', -value=>$new_value, -override=>1)
or
hidden(-name=>'action', -value=>'default_value')
param('hidden_name', $new_value);
This is a try , not sure if it would work.
Try setting hidden variable before button and changing it before every button, so the new value should be taken.
For ex:
<input type='hidden' name='op' value='save'/>
<input type='submit' name='Save Form' value='SaveForm'/>
<input type='hidden' name='op' value='submit'/>
<input type='submit' name='Submit Form' value='SubmitForm'/>
<input type='hidden' name='op' value='cancel'/>
<input type='submit' name='Cancel Form' value='CancelForm'/>
You can check for hidden variable 'op' in perl script.
Posted this to Play user group; I account for the sole view, so hoping to get a view, or perhaps even an answer ;-)
Nested forms are great, but there's one glitch that adds boilerplate to either javascript or scala templates.
For example, given:
#inputText(field = _form("user.email"),
'_label-> "Email Address*",
'class-> "required email",
'placeholder-> "jdoe#gmail.com"
)
the generated input field is something like:
<input id="user_email" name="user.email" ...>
Now, when you want to validate the email address client-side you then have to reference DOM id: $('#user_email')
Where $('#email') would be more natural.
I know I can set the id attrib manually in the template but would prefer to, by default, have the nested name (user in this case) stripped out from the id attrib.
Looking in github views helper directory, I am not finding where I can get access to the generated id (i.e. which file I need to overload and how).
Anyone know how to pull this off and/or have a better approach?
Here is where the field's ID is auto-generated:
https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/scala/play/api/data/Form.scala#L274
There's not really any way you can override that behaviour, but you could write your own #inputText helper that strips the "user_" part from the ID when generating the HTML.
Basically copy-paste the default helper and replace
<input type="text" id="#id" ...
with your own code, e.g.
<input type="text" id="#processFieldId(id)" ...
or (untested!):
<input type="text" id="#(id.split('_').last)" ...
Then just import your custom helper in your template, and use it just like you would use #inputText.
I am building a Lift application, where one of the pages is based on the "File Upload" example from the Lift demo at: http://demo.liftweb.net/file_upload.
If you look at the source code for that page... you see that there is a Lift "snippet" tag, surrounding two "choose" tags:
<lift:snippet type="misc:upload" form="post" multipart="true">
<choose:post>
<p>
File name: <ul:file_name></ul:file_name><br >
MIME Type: <ul:mime_type></ul:mime_type><br >
File length: <ul:length></ul:length><br >
MD5 Hash: <ul:md5></ul:md5><br >
</p>
</choose:post>
<choose:get>
Select a file to upload: <ul:file_upload></ul:file_upload><br >
<input type="submit" value="Upload File">
</choose:get>
</lift:snippet>
The idea is that when a user hits the page for the first time (i.e. a GET request), then Lift will show the form for uploading a file. When the user submits the form (i.e. a POST request to the same page), then Lift instead displays the outcome of the file being processed.
With my application, the new wrinkle is that my "results" POST view needs to also contain a form. I want to provide a text input for the user to enter an email address, and a submit button that when pressed will email information about the processed file:
...
<choose:post>
<p>
File name: <ul:file_name></ul:file_name><br >
MIME Type: <ul:mime_type></ul:mime_type><br >
File length: <ul:length></ul:length><br >
MD5 Hash: <ul:md5></ul:md5><br >
</p>
<!-- BEGIN NEW STUFF -->
Output: <br/>
<textarea rows="30" cols="100"><ul:output></ul:output></textarea>
<br/><br/>
Email the above output to this email address:<br/>
<ul:email/><br/>
<input type="submit" value="Email"/>
<!-- END NEW STUFF -->
</choose:post>
...
However, both the GET and POST versions of this page are wrapped by the same Lift-generated form, which has its "action" set to the same snippet in both cases. How can I change this such that in the POST version, the form's action changes to a different snippet?
In a typical web framework, I would approach something like this with an "onclick" event and two basic lines of JavaScript. However, I haven't even begun to wrap my mind around Lift's... err, interesting notions about writing JavaScript in Scala. Maybe I need to go down that route, or maybe there's a better approach altogether.
First, I will suggest you use Lift's new designer friendly CSS binding instead of the custom XHTML tag.
And one thing you should remember when you're using Lift's snippet, is that it is recursive, you could put an lift snippet inside another snippet's HTML block.
For example, if you wish there is another form after POST, then just put it into the block.
<choose:post>
<p>
File name: <ul:file_name></ul:file_name><br >
MIME Type: <ul:mime_type></ul:mime_type><br >
File length: <ul:length></ul:length><br >
MD5 Hash: <ul:md5></ul:md5><br >
</p>
<!--
The following is same as <lift:snippet type="EMailForm" form="post" multipart="true">
-->
<form action="" method="post" data-lift="EMailForm">
<input type="text" name="email"/>
<input type="submit" />
</form>
</choose:post>
Then deal with the email form action at snippet class EMailForm.
Finally, you may pass the filename / minetype and other information by using hidden form element or SessionVar.
I agree with Brian, use Lift's new designer friendly CSS binding.
Use two separate forms, one for the file upload and one for the submitting the email. Use S.seeOther to redirect the user to the second form when the first has finished processing.
I also prefer the new 'data-lift' HTML attribute.
File upload HTML:
<div data-lift="uploadSnippet?form=post">
<input type="file" id="filename" />
<input type="submit" id="submit" />
</div
File upload snippet:
class uploadSnippet {
def processUpload = {
// do your processing
....
if (success)
S.seeOther("/getemail")
// if processing fails, just allow this method to exit to re-render your
// file upload form
}
def render = {
"#filename" #> SHtml.fileUpload(...) &
"#submit" #> SHtml.submit("Upload", processUpload _ )
}
}
GetEmail HTML:
<div data-lift="getEmailSnippet?form=post">
<input type="text" id="email" />
<input type="submit" id="submit" />
</div
Get Email Snippet:
class getEmailSnippet {
def processSubmit = {
....
}
def render = {
"#email" #> SHtml.text(...) &
"#submit" #> SHtml.submit("Upload", processSubmit _ )
}
There's a bit more on form processing in my blog post on using RequestVar's here:
http://tech.damianhelme.com/understanding-lifts-requestvars
Let me know if you want more detail.
Hope that's useful
Cheers
Damian
If somebody comes up with a more elegant (or "Lift-y") approach within the next few days, then I'll accept their answer. However, I came up with a workaround approach on my own.
I kept the current layout, where the view has a GET block and a POST block both submitting to the same snippet function. The snippet function still has an if-else block, handling each request differently depending on whether it's a GET or POST.
However, now I also have a secondary if-else block inside of the POST's block. This inner if-else looks at the name of the submit button that was clicked. If the submit button was the one for uploading a file, then the snippet handles the uploading and processing of the file. Otherwise, if it was the send email submit button shown after the first POST, then the snippet processes the sending of the email.
Not particularly glamorous, but it works just fine.