virtualcommons-svn Mailing List for Virtual Commons Experiment Software (Page 35)
Status: Beta
Brought to you by:
alllee
You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
(21) |
Aug
(31) |
Sep
(6) |
Oct
(15) |
Nov
(2) |
Dec
(9) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(4) |
Feb
(6) |
Mar
(12) |
Apr
(52) |
May
(14) |
Jun
(19) |
Jul
(81) |
Aug
(115) |
Sep
(36) |
Oct
(88) |
Nov
(46) |
Dec
(58) |
2010 |
Jan
(52) |
Feb
(55) |
Mar
(48) |
Apr
(15) |
May
(5) |
Jun
(38) |
Jul
(27) |
Aug
(24) |
Sep
(28) |
Oct
(1) |
Nov
(2) |
Dec
(29) |
2011 |
Jan
(87) |
Feb
(39) |
Mar
(63) |
Apr
(42) |
May
(26) |
Jun
(53) |
Jul
(23) |
Aug
(43) |
Sep
(37) |
Oct
(25) |
Nov
(4) |
Dec
(7) |
2012 |
Jan
(73) |
Feb
(79) |
Mar
(62) |
Apr
(28) |
May
(12) |
Jun
(2) |
Jul
(9) |
Aug
(1) |
Sep
(8) |
Oct
|
Nov
(3) |
Dec
(3) |
2013 |
Jan
(8) |
Feb
(16) |
Mar
(38) |
Apr
(74) |
May
(62) |
Jun
(15) |
Jul
(49) |
Aug
(19) |
Sep
(9) |
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(25) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <vir...@li...> - 2011-04-08 22:02:38
|
Subject: hg.virtualcommons 322 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/122713a23d01 changeset: 322:122713a23d01 user: Allen Lee <all...@as...> date: Fri Apr 08 12:08:02 2011 -0700 description: adding help text diffstat: vcweb/core/forms.py | 14 ++++++++------ vcweb/core/templates/experimenter/register-participants.html | 3 ++- vcweb/core/templates/includes/form-as-div.html | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diffs (53 lines): diff -r 26d7982ff907 -r 122713a23d01 vcweb/core/forms.py --- a/vcweb/core/forms.py Thu Apr 07 12:39:22 2011 -0700 +++ b/vcweb/core/forms.py Fri Apr 08 12:08:02 2011 -0700 @@ -78,16 +78,18 @@ class RegisterParticipantsForm(forms.ModelForm): experiment_pk = forms.IntegerField(widget=widgets.HiddenInput) - experiment_passcode = forms.CharField(min_length=3, label="Experiment passcode") - institution_name = forms.CharField(min_length=3,label="Institution name") - institution_url = forms.CharField(min_length=3,label='Institution URL') + experiment_passcode = forms.CharField(min_length=3, label="Experiment passcode", help_text='The password used to login to your experiment.') + institution_name = forms.CharField(min_length=3,label="Institution name", + help_text='The name of the institution to be associated with these test participants') + institution_url = forms.CharField(min_length=3,label='Institution URL', + required=False, help_text='A URL, if applicable, for the institution. E.g., http://www.asu.edu') class RegisterSimpleParticipantsForm(RegisterParticipantsForm): - email_suffix = forms.CharField(min_length='3') - number_of_participants = forms.IntegerField(min_value=1) + email_suffix = forms.CharField(min_length='3', help_text='Generated participants will have usernames of the format s1..sn@<email_suffix>. For example, if you register 20 participants with an email suffix of example.edu, the system will generate 20 participants with usernames ranging from s1...@ex..., s2...@ex..., up to s2...@ex....') + number_of_participants = forms.IntegerField(min_value=1, help_text='The number of participants to generate.') class RegisterEmailListParticipantsForm(RegisterParticipantsForm): - participant_emails = EmailListField(label="Participant emails") + participant_emails = EmailListField(label="Participant emails", help_text='A comma or newline delimited list of emails to register as participants for this experiment.') class QuizForm(forms.Form): name_question = forms.CharField(max_length=64, label="What is your name?") diff -r 26d7982ff907 -r 122713a23d01 vcweb/core/templates/experimenter/register-participants.html --- a/vcweb/core/templates/experimenter/register-participants.html Thu Apr 07 12:39:22 2011 -0700 +++ b/vcweb/core/templates/experimenter/register-participants.html Fri Apr 08 12:08:02 2011 -0700 @@ -13,7 +13,8 @@ {% block page %} <form id='register-participants-form' action='' method='post'> <h3>Register participants</h3> - <p>Register participants for {{experiment}} below. <span style='padding: 3px;' class='ui-state-highlight'><b>There are currently {{experiment.participants.count}} registered participants.</b></span> + <p>Please register participants for {{experiment}}. + <span style='padding: 3px;' class='ui-state-highlight'><b>There are currently {{experiment.participants.count}} registered participants.</b></span> {% include "includes/form-as-div.html" %} </form> {% endblock page %} diff -r 26d7982ff907 -r 122713a23d01 vcweb/core/templates/includes/form-as-div.html --- a/vcweb/core/templates/includes/form-as-div.html Thu Apr 07 12:39:22 2011 -0700 +++ b/vcweb/core/templates/includes/form-as-div.html Fri Apr 08 12:08:02 2011 -0700 @@ -5,7 +5,7 @@ {% endif %} {{ field }} {% if field.errors %} -<label class='error' for='id_{{ field.name }}' generated='true'>{{ field.errors|join:". " }}</label> +<label class='error' for='id_{{ field.name }}' title='{{field.help_text}}'>{{ field.errors|join:". " }}</label> {% endif %} </div> {% endfor %} |
From: <vir...@li...> - 2011-04-07 19:41:12
|
Subject: hg.virtualcommons 321 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/26d7982ff907 changeset: 321:26d7982ff907 user: Allen Lee <all...@as...> date: Thu Apr 07 12:39:22 2011 -0700 description: evaluating sphinx for documentation diffstat: docs/Makefile | 130 ++++++++++++++++++++++++++++++++ docs/make.bat | 170 ++++++++++++++++++++++++++++++++++++++++++ docs/source/conf.py | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/source/core.rst | 5 + docs/source/index.rst | 26 ++++++ 5 files changed, 553 insertions(+), 0 deletions(-) diffs (573 lines): diff -r 92263e9ed557 -r 26d7982ff907 docs/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/Makefile Thu Apr 07 12:39:22 2011 -0700 @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/vcweb.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/vcweb.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/vcweb" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/vcweb" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff -r 92263e9ed557 -r 26d7982ff907 docs/make.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/make.bat Thu Apr 07 12:39:22 2011 -0700 @@ -0,0 +1,170 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^<target^>` where ^<target^> is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\vcweb.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\vcweb.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff -r 92263e9ed557 -r 26d7982ff907 docs/source/conf.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/source/conf.py Thu Apr 07 12:39:22 2011 -0700 @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +# +# vcweb documentation build configuration file, created by +# sphinx-quickstart on Thu Apr 7 10:31:14 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('../..')) +os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['.templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'vcweb' +copyright = u'2011, Allen Lee' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['.static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'vcwebdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'vcweb.tex', u'vcweb Documentation', + u'Allen Lee', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'vcweb', u'vcweb Documentation', + [u'Allen Lee'], 1) +] + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff -r 92263e9ed557 -r 26d7982ff907 docs/source/core.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/source/core.rst Thu Apr 07 12:39:22 2011 -0700 @@ -0,0 +1,5 @@ +VCWEB Core +========== + +.. automodule:: vcweb.core.models + :members: diff -r 92263e9ed557 -r 26d7982ff907 docs/source/index.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/source/index.rst Thu Apr 07 12:39:22 2011 -0700 @@ -0,0 +1,26 @@ +.. vcweb documentation master file, created by + sphinx-quickstart on Thu Apr 7 10:31:14 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +The Virtual Commons Web Experiments (VCWEB) +================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + + intro + tutorial + core + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + |
From: <vir...@li...> - 2011-04-07 19:41:12
|
Subject: hg.virtualcommons 320 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/92263e9ed557 changeset: 320:92263e9ed557 user: Allen Lee <all...@as...> date: Thu Apr 07 12:38:02 2011 -0700 description: adding exception handling middleware diffstat: vcweb/core/middleware.py | 11 +++++++++++ vcweb/core/templates/base.html | 4 ++-- vcweb/settings.py | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diffs (42 lines): diff -r 1b8c3e168d32 -r 92263e9ed557 vcweb/core/middleware.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/middleware.py Thu Apr 07 12:38:02 2011 -0700 @@ -0,0 +1,11 @@ +from django.core.exceptions import PermissionDenied +from django.shortcuts import redirect +from django.contrib import messages + +class ExceptionHandlingMiddleware(object): + def process_exception(self, request, exception): + if type(exception) == PermissionDenied: + if request.user.is_authenticated(): + messages.warning(request, exception) + return redirect('core:dashboard') + return None diff -r 1b8c3e168d32 -r 92263e9ed557 vcweb/core/templates/base.html --- a/vcweb/core/templates/base.html Thu Apr 07 00:02:10 2011 -0700 +++ b/vcweb/core/templates/base.html Thu Apr 07 12:38:02 2011 -0700 @@ -44,10 +44,10 @@ <div id='page'> {% if messages %} <h3>Notifications</h3> - <ul class="messages"> + <ul id='messages' class="messages"> {% for message in messages %} <li{% if message.tags %} class="{{ message.tags }}"{% endif %}> - <span class='ui-icon ui-icon-alert'></span>{{ message }}</li> + <span class='icon-left ui-icon ui-icon-alert'></span>{{ message }}</li> {% endfor %} </ul> {% endif %} diff -r 1b8c3e168d32 -r 92263e9ed557 vcweb/settings.py --- a/vcweb/settings.py Thu Apr 07 00:02:10 2011 -0700 +++ b/vcweb/settings.py Thu Apr 07 12:38:02 2011 -0700 @@ -80,6 +80,7 @@ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', + 'vcweb.core.middleware.ExceptionHandlingMiddleware', ) ROOT_URLCONF = 'vcweb.urls' |
From: <vir...@li...> - 2011-04-07 06:58:46
|
Subject: hg.virtualcommons 319 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/1b8c3e168d32 changeset: 319:1b8c3e168d32 user: Allen Lee <all...@as...> date: Thu Apr 07 00:02:10 2011 -0700 description: adding basic participant registration forms diffstat: vcweb/core/forms.py | 15 +- vcweb/core/templates/base-vcweb-form.html | 2 +- vcweb/core/templates/experimenter/dashboard.html | 5 +- vcweb/core/templates/experimenter/register-email-participants.html | 2 + vcweb/core/templates/experimenter/register-participants.html | 19 ++ vcweb/core/templates/experimenter/register-simple-participants.html | 2 + vcweb/core/templates/includes/form-as-div.html | 2 + vcweb/core/templates/includes/jquery.forms.html | 1 + vcweb/core/urls.py | 6 +- vcweb/core/views.py | 90 ++++----- vcweb/static/css/style.css | 2 +- 11 files changed, 90 insertions(+), 56 deletions(-) diffs (284 lines): diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/forms.py --- a/vcweb/core/forms.py Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/core/forms.py Thu Apr 07 00:02:10 2011 -0700 @@ -76,9 +76,18 @@ raise ValidationError(_(u'%s is not a valid email address.' % email)) return emails -class ConfigureExperimentForm(forms.Form): - clone_experiment = forms.NullBooleanField(label="Clone this experiment?") - registered_participants = EmailListField(label="Registered participants") +class RegisterParticipantsForm(forms.ModelForm): + experiment_pk = forms.IntegerField(widget=widgets.HiddenInput) + experiment_passcode = forms.CharField(min_length=3, label="Experiment passcode") + institution_name = forms.CharField(min_length=3,label="Institution name") + institution_url = forms.CharField(min_length=3,label='Institution URL') + +class RegisterSimpleParticipantsForm(RegisterParticipantsForm): + email_suffix = forms.CharField(min_length='3') + number_of_participants = forms.IntegerField(min_value=1) + +class RegisterEmailListParticipantsForm(RegisterParticipantsForm): + participant_emails = EmailListField(label="Participant emails") class QuizForm(forms.Form): name_question = forms.CharField(max_length=64, label="What is your name?") diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/base-vcweb-form.html --- a/vcweb/core/templates/base-vcweb-form.html Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/core/templates/base-vcweb-form.html Thu Apr 07 00:02:10 2011 -0700 @@ -2,5 +2,5 @@ {% block head %} {{ block.super }} - <script type='text/javascript' src='/static/js/jquery.validate.min.js'></script> + {% include "includes/jquery.forms.html" %} {% endblock head %} diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/experimenter/dashboard.html --- a/vcweb/core/templates/experimenter/dashboard.html Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/core/templates/experimenter/dashboard.html Thu Apr 07 00:02:10 2011 -0700 @@ -47,14 +47,14 @@ <li><a class='confirm-experiment-action' title='Creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> {% if e.participants.count == 0 %} <li> - <a title='Configure this experiment' href='{{e.controller_url}}/configure'><img src='/static/images/famfamfam/database_gear.png' alt='configure'/> configure</a> + <a title='Register participants' href='{{e.controller_url}}/register-simple'><img src='/static/images/famfamfam/group_add.png' alt='register'/> register participants</a> </li> <li> <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> </li> {% else %} - <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> + <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/group_del.png' alt=''/> clear all participants</a></li> {% endif %} <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> {% if e.is_active %} @@ -69,4 +69,3 @@ {% endfor %} </div> {% endblock page %} - diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/experimenter/register-email-participants.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter/register-email-participants.html Thu Apr 07 00:02:10 2011 -0700 @@ -0,0 +1,2 @@ +{% extends "experimenter/register-participants.html" %} + diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/experimenter/register-participants.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter/register-participants.html Thu Apr 07 00:02:10 2011 -0700 @@ -0,0 +1,19 @@ +{% extends "experimenter/base.html" %} + +{% block title %}Register participants for {{ experiment }} {% endblock %} +{% block head %} +{{ block.super }} +{% include "includes/jquery.forms.html" %} +<script type='text/javascript'> + $(function() { + + }); +</script> +{% endblock %} +{% block page %} +<form id='register-participants-form' action='' method='post'> + <h3>Register participants</h3> + <p>Register participants for {{experiment}} below. <span style='padding: 3px;' class='ui-state-highlight'><b>There are currently {{experiment.participants.count}} registered participants.</b></span> + {% include "includes/form-as-div.html" %} +</form> +{% endblock page %} diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/experimenter/register-simple-participants.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter/register-simple-participants.html Thu Apr 07 00:02:10 2011 -0700 @@ -0,0 +1,2 @@ +{% extends "experimenter/register-participants.html" %} + diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/includes/form-as-div.html --- a/vcweb/core/templates/includes/form-as-div.html Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/core/templates/includes/form-as-div.html Thu Apr 07 00:02:10 2011 -0700 @@ -1,6 +1,8 @@ {% for field in form %} <div class='field'> +{% if not field.is_hidden %} <span class='label'>{{ field.label_tag }}:</span> +{% endif %} {{ field }} {% if field.errors %} <label class='error' for='id_{{ field.name }}' generated='true'>{{ field.errors|join:". " }}</label> diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/templates/includes/jquery.forms.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/includes/jquery.forms.html Thu Apr 07 00:02:10 2011 -0700 @@ -0,0 +1,1 @@ +<script type='text/javascript' src='/static/js/jquery.validate.min.js'></script> diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/urls.py --- a/vcweb/core/urls.py Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/core/urls.py Thu Apr 07 00:02:10 2011 -0700 @@ -1,6 +1,7 @@ from django.conf.urls.defaults import patterns, url from django.contrib.auth.decorators import login_required -from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, ConfigureExperimentView, CloneExperimentView +from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, CloneExperimentView, \ + RegisterEmailListView, RegisterSimpleParticipantsView ''' URLs defined by the core vcweb app. ''' @@ -13,7 +14,8 @@ url(r'^participate/(?P<pk>\d+)/instructions', 'instructions', name='instructions'), url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/(?P<pk>\d+)/monitor$', MonitorExperimentView.as_view(), name='monitor_experiment'), - url(r'^experiment/(?P<pk>\d+)/configure$', ConfigureExperimentView.as_view(), name='configure_experiment'), + url(r'^experiment/(?P<pk>\d+)/register-by-emails$', RegisterEmailListView.as_view(), name='register_by_emails'), + url(r'^experiment/(?P<pk>\d+)/register-simple$', RegisterSimpleParticipantsView.as_view(), name='register_simple'), url(r'^experiment/(?P<pk>\d+)/clone$', CloneExperimentView.as_view(), name='clone'), # url(r'^experiment/(?P<pk>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), # url(r'^experiment/(?P<pk>\d+)/clear-participants', 'clear_participants', name='clear_participants'), diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/core/views.py --- a/vcweb/core/views.py Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/core/views.py Thu Apr 07 00:02:10 2011 -0700 @@ -2,15 +2,19 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.core.urlresolvers import reverse +from django.core.exceptions import PermissionDenied from django.http import HttpResponse from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext from django.utils.decorators import method_decorator from django.views.generic import ListView, FormView, TemplateView from django.views.generic.base import TemplateResponseMixin -from django.views.generic.detail import SingleObjectMixin -from vcweb.core.forms import RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm, ConfigureExperimentForm -from vcweb.core.models import Participant, Experiment, Institution, is_participant, is_experimenter +from django.views.generic.detail import SingleObjectMixin, DetailView +from django.views.generic.edit import BaseUpdateView, UpdateView +from vcweb.core.forms import (RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm, + RegisterEmailListParticipantsForm, RegisterSimpleParticipantsForm) +from vcweb.core.models import (Participant, Experiment, Institution, ParticipantExperimentRelationship, + is_participant, is_experimenter) from vcweb.core.decorators import anonymous_required, experimenter_required, participant_required import hashlib import base64 @@ -124,7 +128,6 @@ return render_to_response(experiment.get_template_path('instructions.html'), locals(), context_instance=RequestContext(request)) - """ experimenter views FIXME: add has_perms authorization to ensure that only experimenters can access @@ -142,18 +145,7 @@ def process_experiment(self, experiment): pass def check_user(self, user, experiment): - pass - - def get(self, request, **kwargs): - try: - self.object = self.get_object() - self.process_experiment(self.object) - context = self.get_context_data(object=self.object) - return self.render_to_response(context) - except Experiment.DoesNotExist as e: - logger.warning(e) - messages.warning(request, e) - return redirect( reverse('core:dashboard') ) + return experiment def get_object(self, queryset=None): pk = self.kwargs.get('pk', None) @@ -164,47 +156,53 @@ class ParticipantSingleExperimentMixin(SingleExperimentMixin, ParticipantMixin): def check_user(self, user, experiment): # FIXME: should we do a user.participant in experiment.participants.all() check? - pass + return experiment class ExperimenterSingleExperimentMixin(SingleExperimentMixin, ExperimenterMixin): def check_user(self, user, experiment): if self.request.user.experimenter.pk == experiment.experimenter.pk: return experiment - raise Experiment.DoesNotExist("You do not have access to %s" % experiment) + raise PermissionDenied("You do not have access to %s" % experiment) -class MonitorExperimentView(ExperimenterSingleExperimentMixin, TemplateView): +class MonitorExperimentView(ExperimenterSingleExperimentMixin, DetailView): template_name = 'experimenter/monitor.html' -class ConfigureExperimentView(ExperimenterSingleExperimentMixin, FormView): - form_class = ConfigureExperimentForm - template_name = 'experimenter/register-participants.html' +class RegisterEmailListView(ExperimenterSingleExperimentMixin, UpdateView): + form_class = RegisterEmailListParticipantsForm + template_name = 'experimenter/register-email-participants.html' def form_valid(self, form): - request = self.request + emails = form['participant_emails'] + experiment = self.object + logger.debug("registering participants %s for experiment: %s" % (emails, experiment)) + experiment.authentication_code = form['experiment_passcode'] + for email in emails: + try: + participant = Participant.objects.get(user__email=email) + except Participant.DoesNotExist: + user = User.objects.create_user(username=email, email=email, + password=experiment.authentication_code) + participant = Participant.objects.create(user=user) - @experimenter_required - def add_participants(request, pk=None, count=0): - try: - experiment = _get_experiment(request, pk) - count = int(count) - if count > 0: - experiment.setup_test_participants(count=count) - except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % pk - logger.warning(error_message) - messages.warning(request, error_message) - return redirect('core:dashboard') + ParticipantExperimentRelationship.objects.create(participant=participant, + experiment=experiment, + created_by=experiment.experimenter.user) - @experimenter_required - def clear_participants(request, pk=None): - try: - experiment = _get_experiment(request, pk) - if experiment.participants.count() > 0: - experiment.participants.all().delete() - except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % pk - logger.warning(error_message) - messages.warning(request, error_message) - return redirect('core:dashboard') + +class RegisterSimpleParticipantsView(ExperimenterSingleExperimentMixin, BaseUpdateView, TemplateResponseMixin): + form_class = RegisterSimpleParticipantsForm + template_name = 'experimenter/register-simple-participants.html' + def form_valid(self, form): + number_of_participants = form['number_of_participants'] + email_suffix = form['email_suffix'] + experiment = self.object + experiment_passcode = form['experiment_passcode'] + institution_name = form['institution_name'] + institution_url = form['institution_url'] + experiment.setup_test_participants(count=number_of_participants, + institution_name=institution_name, + institution_url=institution_url, + email_suffix=email_suffix, + test_password=experiment_passcode) # FIXME: uses GET (which should be idempotent) to modify database state which makes HTTP sadful class CloneExperimentView(ExperimenterSingleExperimentMixin, TemplateView): diff -r 530087acf7e7 -r 1b8c3e168d32 vcweb/static/css/style.css --- a/vcweb/static/css/style.css Mon Apr 04 14:13:08 2011 -0700 +++ b/vcweb/static/css/style.css Thu Apr 07 00:02:10 2011 -0700 @@ -48,7 +48,7 @@ span.label { float: left; text-align: right; - width: 11em; + width: 13em; font-weight: bolder; margin-top: 0.37em; margin-right: 0.37em; |
From: <vir...@li...> - 2011-04-07 06:58:46
|
Subject: hg.virtualcommons 318 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/530087acf7e7 changeset: 318:530087acf7e7 user: Allen Lee <all...@as...> date: Mon Apr 04 14:13:08 2011 -0700 description: restructuring template directories in the core app, adding participant and experiment subdirectories. diffstat: vcweb/core/templates/base-experimenter.html | 13 - vcweb/core/templates/base-participant.html | 24 - vcweb/core/templates/chat.html | 36 -- vcweb/core/templates/experimenter-dashboard.html | 72 ----- vcweb/core/templates/experimenter/base.html | 13 + vcweb/core/templates/experimenter/dashboard.html | 72 +++++ vcweb/core/templates/experimenter/monitor.html | 256 +++++++++++++++++++ vcweb/core/templates/monitor.html | 256 ------------------- vcweb/core/templates/participant-dashboard.html | 38 -- vcweb/core/templates/participant/base.html | 24 + vcweb/core/templates/participant/dashboard.html | 38 ++ vcweb/core/urls.py | 8 +- vcweb/core/views.py | 99 +++--- vcweb/forestry/templates/forestry/chat.html | 2 +- vcweb/forestry/templates/forestry/experimenter-index.html | 2 +- vcweb/forestry/templates/forestry/instructions.html | 2 +- vcweb/forestry/templates/forestry/manage-experiment.html | 2 +- vcweb/forestry/templates/forestry/participant-index.html | 6 +- vcweb/forestry/templates/forestry/participate.html | 2 +- vcweb/forestry/templates/forestry/quiz.html | 2 +- vcweb/forestry/templates/forestry/wait.html | 2 +- vcweb/forestry/views.py | 9 +- vcweb/vcweb-tornadio.py | 6 +- vcweb/vcweb-tornado.py | 150 ----------- 24 files changed, 476 insertions(+), 658 deletions(-) diffs (1348 lines): diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/base-experimenter.html --- a/vcweb/core/templates/base-experimenter.html Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -{% extends "base.html" %} -{% block head %} -{{ block.super}} -<script type='text/javascript'> - var qtipOptions = {position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'dark', tip: 'bottomMiddle'} }; - $(function() { - $('[title]').qtip(qtipOptions); - }); -</script> -{% include "includes/jquery.confirm.html" %} -{% endblock %} -{% block title %}Virtual Commons Web Experimenter Interface{% endblock %} -{% block header %}{% include "includes/experimenter-nav-menu.html" %}{% endblock %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/base-participant.html --- a/vcweb/core/templates/base-participant.html Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - {{block.super}} - {% block participant_socket_io %} - <script type='text/javascript' src='/static/js/jquery.validate.min.js'></script> - {% include "includes/participant.events.html" %} - {% include "includes/socket.io.html" %} - <script type='text/javascript'> - connect(window.location.hostname, 8888, 'participant/{{participant_experiment_relationship.pk}}'); - </script> - {% endblock %} -{% endblock %} - -{% block title %} - Virtual Commons Web Participant Interface -{% endblock %} - -{% block header %} - {% include "includes/participant-nav-menu.html" %} -{% endblock %} - - - diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/chat.html --- a/vcweb/core/templates/chat.html Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -{% extends "base-participant.html" %} - -{% block head %} - {{ block.super }} - {% include "includes/socket.io.html" %} - <script type="text/javascript"> - $(function() { - var s = connect("libai.la.asu.edu", 8888); - s.on('message', function(data) { - $("#chat").append("<div>" + data + "</div>"); - }); - - //send the message when submit is clicked - $('#chatform').submit(function (evt) { - var line = $('#chattext').val() - $('#chattext').val('') - console.log("sending line: " + line); - s.send(createMessageEvent(line)); - return false; - }); - $('#chattext').focus(); - }); - </script> -{% endblock %} - -{% block content %} - <h3>Chat</h3> - <div id="chat" style="width: 60em; height: 20em; overflow:auto; border: 1px dashed black"> - </div> - <form id="chatform"> - <input id='chattext' type="text" /> - <input type="submit" /> - </form> -{% endblock %} - - diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/experimenter-dashboard.html --- a/vcweb/core/templates/experimenter-dashboard.html Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -{% extends "base-experimenter.html" %} -{% block title %}Virtual Commons Web Experimenter Dashboard{% endblock %} -{% block head %} -{{ block.super }} -<script type='text/javascript'> - $(function() { - $('.confirm-experiment-action').each(function() { - var confirmable = $(this); - var description = confirmable.attr("title"); - confirmable.click(function() { - confirmable.fastConfirm({ - questionText: description + " - continue?", - onProceed: function(trigger) { - $(trigger).fastConfirm('close'); - window.location = $(trigger).attr("href"); - }, - onCancel: function(trigger) { - $(trigger).fastConfirm('close'); - } - }); - return false; - }); - }); - }); -</script> -{% endblock %} -{% block page %} -{{ block.super }} -{% comment%} -FIXME: replace these links eventually. -{% endcomment %} -<div id='navmenu'> - <a href='/admin'>add / configure an experiment</a> - <a href='/contact'>report a bug</a> -</div> -<div class='ui-state-highlight ui-corner-all'> - <span class='ui-icon ui-icon-info icon-left'></span> - Welcome to the experimenter dashboard. You are logged in as {{request.user.experimenter}}. -</div> -<h3>Your experiments</h3> -<div id="post"> - {% for e in experiments %} - <div class='notice ui-corner-all'> - {{e.status_line}} <span style='padding: 3px;' class='ui-state-highlight'><b>{{e.participants.count}} registered participants</b></span> - <ul class='horizontal'> - <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> - <li><a class='confirm-experiment-action' title='Creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> - {% if e.participants.count == 0 %} - <li> - <a title='Configure this experiment' href='{{e.controller_url}}/configure'><img src='/static/images/famfamfam/database_gear.png' alt='configure'/> configure</a> - </li> - <li> - <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> - <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> - </li> - {% else %} - <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> - {% endif %} - <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> - {% if e.is_active %} - <li><a title='stop this experiment' href='{{e.stop_url}}' class='confirm-experiment-action' style='background-image:none;' ><img src='/static/images/famfamfam/stop.png' alt=''/> stop</a></li> - {% endif %} - </ul> - </div> - {% empty %} - <div class='info infoIcon ui-corner-all'> - You are not currently running any experiments. - </div> - {% endfor %} -</div> -{% endblock page %} - diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/experimenter/base.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter/base.html Mon Apr 04 14:13:08 2011 -0700 @@ -0,0 +1,13 @@ +{% extends "base.html" %} +{% block head %} +{{ block.super}} +<script type='text/javascript'> + var qtipOptions = {position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'dark', tip: 'bottomMiddle'} }; + $(function() { + $('[title]').qtip(qtipOptions); + }); +</script> +{% include "includes/jquery.confirm.html" %} +{% endblock %} +{% block title %}Virtual Commons Web Experimenter Interface{% endblock %} +{% block header %}{% include "includes/experimenter-nav-menu.html" %}{% endblock %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/experimenter/dashboard.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter/dashboard.html Mon Apr 04 14:13:08 2011 -0700 @@ -0,0 +1,72 @@ +{% extends "experimenter/base.html" %} +{% block title %}Virtual Commons Web Experimenter Dashboard{% endblock %} +{% block head %} +{{ block.super }} +<script type='text/javascript'> + $(function() { + $('.confirm-experiment-action').each(function() { + var confirmable = $(this); + var description = confirmable.attr("title"); + confirmable.click(function() { + confirmable.fastConfirm({ + questionText: description + " - continue?", + onProceed: function(trigger) { + $(trigger).fastConfirm('close'); + window.location = $(trigger).attr("href"); + }, + onCancel: function(trigger) { + $(trigger).fastConfirm('close'); + } + }); + return false; + }); + }); + }); +</script> +{% endblock %} +{% block page %} +{{ block.super }} +{% comment%} +FIXME: replace these links eventually. +{% endcomment %} +<div id='navmenu'> + <a href='/admin'>add / configure an experiment</a> + <a href='/contact'>report a bug</a> +</div> +<div class='ui-state-highlight ui-corner-all'> + <span class='ui-icon ui-icon-info icon-left'></span> + Welcome to the experimenter dashboard. You are logged in as {{request.user.experimenter}}. +</div> +<h3>Your experiments</h3> +<div id="post"> + {% for e in experiments %} + <div class='notice ui-corner-all'> + {{e.status_line}} <span style='padding: 3px;' class='ui-state-highlight'><b>{{e.participants.count}} registered participants</b></span> + <ul class='horizontal'> + <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> + <li><a class='confirm-experiment-action' title='Creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> + {% if e.participants.count == 0 %} + <li> + <a title='Configure this experiment' href='{{e.controller_url}}/configure'><img src='/static/images/famfamfam/database_gear.png' alt='configure'/> configure</a> + </li> + <li> + <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> + <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> + </li> + {% else %} + <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> + {% endif %} + <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> + {% if e.is_active %} + <li><a title='stop this experiment' href='{{e.stop_url}}' class='confirm-experiment-action' style='background-image:none;' ><img src='/static/images/famfamfam/stop.png' alt=''/> stop</a></li> + {% endif %} + </ul> + </div> + {% empty %} + <div class='info infoIcon ui-corner-all'> + You are not currently running any experiments. + </div> + {% endfor %} +</div> +{% endblock page %} + diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/experimenter/monitor.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter/monitor.html Mon Apr 04 14:13:08 2011 -0700 @@ -0,0 +1,256 @@ +{% extends "experimenter/base.html" %} +{% block head %} +{{ block.super }} +{% include "includes/experimenter.events.html" %} +{% include "includes/socket.io.html" %} +<script type='text/javascript'> + function update(json) { + if (json == Dajaxice.EXCEPTION) { + console.error("dajaxice error: " + json); + } + else { + $('#statusDiv').html(json.status); + $('#experimentData').accordion("destroy"); + $('#experimentData').html(json.experimentData); + registerCallbacks(json.round_data_count, json.active_round_number); + } + } + function registerCallbacks(round_data_count, active_round_number) { + $('.confirm-experiment-action').each(function() { + var confirmable = $(this); + var description = confirmable.attr("title"); + var action= $(this).attr("name"); + confirmable.click(function() { + confirmable.fastConfirm({ + questionText: description + " - continue?", + onProceed: function(trigger) { + Dajaxice.vcweb.core.experiment_controller(update, {'experiment_id': {{experiment_id}}, 'action':action}); + $('#statusDiv').hide('fast'); + $('#experimentData').hide('fast'); + $('#statusSpinner').show('fast'); + $(trigger).fastConfirm('close'); + }, + onCancel: function(trigger) { + $(trigger).fastConfirm('close'); + } + }); + return false; + }); + }); + $('#statusSpinner').hide(); + $('#statusDiv').show('fast'); + $('#experimentData').show('fast'); + $('#statusDiv [title]').qtip(qtipOptions); + if (round_data_count > 0) { + $('#experimentData').accordion({ + active: active_round_number - 1, + autoHeight: false + }); + } + } + function addExperimentMessage(message) { + $("#experiment-messages").append($("<div style='font-size: 0.8em;line-height:0.9em;padding:3px;' class='ui-state-highlight' />").append(message)); + } + $(function() { + var experimentMessageDiv = document.getElementById('experiment-messages'); + registerCallbacks({{ experiment.round_data.count }}, {{ experiment.current_round.sequence_number }}); + // socket.io connection + // FIXME: add auth + var s = connect(window.location.hostname, 8888, 'experimenter/{{request.user.experimenter.pk}}'); + s.on('message', function(json_string) { + console.log("Received message: " + json_string); + var json = jQuery.parseJSON(json_string); + switch (json.message_type) { + case 'info': + addExperimentMessage(json.message); + break; + case 'chat': + break; + case 'submit': + $('#participant_data_value_' + json.participant_data_value_pk).html(json.message).effect("highlight", {}, 5000); + addExperimentMessage("Participant " + json.participant_number + " (Group #" + json.participant_group + + ") submit a harvest decision of " + json.message); + break; + default: + } + scrollToBottom(experimentMessageDiv); + }); + $('#refreshAllParticipants').click(function(evt) { + console.log("sending refresh event"); + s.send(createRefreshEvent()); + return false; + }); + $('#gotoUrl').click(function(evt) { + console.log("sending goto event"); + s.send(createGotoEvent()); + return false; + }); + scrollToBottom(experimentMessageDiv); + }); +</script> +{% endblock %} +{% block title %} +{{ experiment.status_line }} +{% endblock %} +{% block page %} +{{block.super}} +<h3>{{experiment}}</h3> +<span>You are logged in as {{request.user.experimenter}}.</span> +<hr/> +<div id='experimenter-sidebar'> + <h5>Activity Log</h5> + <div id='experiment-messages' class='experimenter-sidebar-messages notice ui-corner-all'> + {% for group in experiment.groups.all %} + {% for activity_log in group.current_round_activity_log %} + <div style='font-size: 0.75em; line-height: 1.0em;padding:3px;' class='ui-state-highlight'> + {{activity_log}} + </div> + {% endfor %} + {% endfor %} + </div> +</div> +<fieldset class='small ui-corner-all'> + <legend>Experiment management</legend> + <ul class='actions'> + <li><span id='refreshAllParticipants' title='Sends a page refresh to all connected participants.' class='clickable' > + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_refresh.png);'></span> + refresh all participants</span> + </li> + <li><span id='gotoUrl' title='Moves all connected participants from waiting page to active page.' class='clickable' > + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_right.png);'></span> + transition all participants to next round</span> + </li> + <li> + <a href='download/csv'> + <span class='vcweb-icon ui-icon icon-left' style='margin: 8px 0.15em 0px 0px; background:url(/static/images/download-icon.png);'></span> + download data as <img src='/static/images/famfamfam/page_white_text.png' style='margin: 5px 0 0 0;' alt='' /> csv + </a> | + <a href='download/xls'><img src='/static/images/famfamfam/page_white_excel.png' style='margin: 5px 0 0 0;' alt=''/> xls</a> + </li> + </ul> +</fieldset> +<div class='experiment-dashboard'> + {% comment %} + FIXME: Improve this so that we can just inject a new round_configuration + JSON object in and everything auto-updates. + {% endcomment %} + <div id='statusSpinner' style='display:none;'> + <img src='/static/images/squares-circle-ajax-loader.gif' alt='... working ...' /> + </div> + <div id='statusDiv'> + {% block status %} + {% with participant_count=experiment.participants.count %} + <fieldset class='small ui-corner-all'> + <legend>round status</legend> + <ul id='actions' class='actions'> + {% if experiment.is_active %} + {% if experiment.is_round_in_progress %} + <li><a class='confirm-experiment-action' name='end_round' href='end-round' title='Stops the current round.'> + <span class='vcweb-icon icon-left ui-icon' style='background: url(/static/images/famfamfam/control_stop_blue.png);' ></span>end round</a></li> + {% else %} + <li><a class='confirm-experiment-action' name='start_round' href='start-round' title='Starts the round.'> + <span class='ui-icon vcweb-icon icon-left' style='background:url(/static/images/famfamfam/control_play_blue.png);' ></span>start round</a></li> + {% endif %} + <li><a class='confirm-experiment-action' name='advance_to_next_round' href='advance-to-next-round' title='Stops the current round if necessary and advances to the next round.'> + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/control_fastforward_blue.png);' ></span>advance to next round</a></li> + {% else %} + {% if participant_count == 0 %} + <div class='alert alertIcon ui-corner-all'> + There are no registered participants. Please <a href='{% url core:dashboard %}'>return to the dashboard to register participants.</a> + </div> + {% else %} + <li><a title='You must first activate an experiment before you can run it.' class='confirm-experiment-action' name='activate' + href='activate'><span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' ></span>activate</a> + </li> + {%endif%} + {% endif %} + </ul> + <br/> + <ul class='messages'> + <li title='{{experiment.actions_help_text}}'>{{ experiment.round_status_display }}</li> + <li>Type: {{ experiment.current_round.get_round_type_display }}</li> + <li>Round started on {{ experiment.current_round_start_time }}</li> + <li>Time remaining: {{ experiment.time_remaining }}</li> + <li>Registered participants: <b>{{participant_count}}</b> + </li> + </ul> + </fieldset> + {% endwith %} + {% endblock status %} + </div> +</div> +<div id='experimentData'> + {% block data %} + {% for round_data in experiment.round_data.all %} + <h3><a href='#'>{{ round_data }}</a></h3> + <div id='round_data_{{forloop.counter}}'> + {% if round_data.group_data_values.count > 0 %} + <h4 class='collapsible'>Group data</h4> + <table> + <thead> + <tr><th>Group</th><th>Parameter Name</th><th>Value</th></tr> + </thead> + <tbody> + {% for group_data_value in round_data.group_data_values.all %} + <tr> + <td> + <a class='tooltip' title='{{ group_data_value.group.all_participants_str }}'> + {{ group_data_value.group }} + </a> + </td> + <td>{{ group_data_value.parameter.label}}</td> + <td>{{ group_data_value.value}}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <div class='info ui-corner-all'> + <span class='ui-icon ui-icon-info icon-left'></span>No group data for this round. + </div> + {% endif %} + {% comment %} participant data values {% endcomment %} + {% if round_data.participant_data_values.count > 0 %} + <h4>Participant data</h4> + <table> + <thead> + <tr><th>Participant</th><th>Parameter name</th><th>Value</th><th>Type</th></tr> + </thead> + <tbody> + {% for participant_data_value in round_data.participant_data_values.all %} + <tr> + <td> + <a class='tooltip' title='{{participant_data_value.participant}}'> + {{ participant_data_value.participant_number }} ({{ participant_data_value.group }}) + </a> + </td> + <td>{{ participant_data_value.parameter.label }}</td> + <td id='participant_data_value_{{participant_data_value.pk}}'>{{ participant_data_value.value }}</td> + <td>{{ participant_data_value.parameter.type }}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <div class='info ui-corner-all'><span class='ui-icon ui-icon-info icon-left'></span>No participant data for this round.</div> + {% endif %} + {% comment %} participant chats {% endcomment %} + {% if round_data.chat_messages.count > 0 %} + <h4 class='collapsible'>Chat data (click to hide)</h4> + <div id='chat_{{round_data.pk}}' class='chat notice ui-corner-all'> + {% for chat_message in round_data.chat_messages.all %} + <div class='ui-state-highlight'> + <a class='tooltip' name='{{chat_message.pk}}' title='{{chat_message.date_created}} {{chat_message.participant}}'> + {{chat_message.date_created|date:"H:s"}}</a> | {{chat_message}} + <span class='ui-icon ui-icon-comment icon-right'></span> + </div> + {% endfor %} + </div> + {% endif %} + </div> + {% empty %} + <div class='alert ui-state-highlight ui-corner-all'><span class='ui-icon ui-icon-alert icon-left'></span>Round data is not yet available.</div> + {% endfor %} + {% endblock data %} +</div> +{% endblock page %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,256 +0,0 @@ -{% extends "base-experimenter.html" %} -{% block head %} -{{ block.super }} -{% include "includes/experimenter.events.html" %} -{% include "includes/socket.io.html" %} -<script type='text/javascript'> - function update(json) { - if (json == Dajaxice.EXCEPTION) { - console.error("dajaxice error: " + json); - } - else { - $('#statusDiv').html(json.status); - $('#experimentData').accordion("destroy"); - $('#experimentData').html(json.experimentData); - registerCallbacks(json.round_data_count, json.active_round_number); - } - } - function registerCallbacks(round_data_count, active_round_number) { - $('.confirm-experiment-action').each(function() { - var confirmable = $(this); - var description = confirmable.attr("title"); - var action= $(this).attr("name"); - confirmable.click(function() { - confirmable.fastConfirm({ - questionText: description + " - continue?", - onProceed: function(trigger) { - Dajaxice.vcweb.core.experiment_controller(update, {'experiment_id': {{experiment_id}}, 'action':action}); - $('#statusDiv').hide('fast'); - $('#experimentData').hide('fast'); - $('#statusSpinner').show('fast'); - $(trigger).fastConfirm('close'); - }, - onCancel: function(trigger) { - $(trigger).fastConfirm('close'); - } - }); - return false; - }); - }); - $('#statusSpinner').hide(); - $('#statusDiv').show('fast'); - $('#experimentData').show('fast'); - $('#statusDiv [title]').qtip(qtipOptions); - if (round_data_count > 0) { - $('#experimentData').accordion({ - active: active_round_number - 1, - autoHeight: false - }); - } - } - function addExperimentMessage(message) { - $("#experiment-messages").append($("<div style='font-size: 0.8em;line-height:0.9em;padding:3px;' class='ui-state-highlight' />").append(message)); - } - $(function() { - var experimentMessageDiv = document.getElementById('experiment-messages'); - registerCallbacks({{ experiment.round_data.count }}, {{ experiment.current_round.sequence_number }}); - // socket.io connection - // FIXME: add auth - var s = connect(window.location.hostname, 8888, 'experimenter/{{request.user.experimenter.pk}}'); - s.on('message', function(json_string) { - console.log("Received message: " + json_string); - var json = jQuery.parseJSON(json_string); - switch (json.message_type) { - case 'info': - addExperimentMessage(json.message); - break; - case 'chat': - break; - case 'submit': - $('#participant_data_value_' + json.participant_data_value_pk).html(json.message).effect("highlight", {}, 5000); - addExperimentMessage("Participant " + json.participant_number + " (Group #" + json.participant_group + - ") submit a harvest decision of " + json.message); - break; - default: - } - scrollToBottom(experimentMessageDiv); - }); - $('#refreshAllParticipants').click(function(evt) { - console.log("sending refresh event"); - s.send(createRefreshEvent()); - return false; - }); - $('#gotoUrl').click(function(evt) { - console.log("sending goto event"); - s.send(createGotoEvent()); - return false; - }); - scrollToBottom(experimentMessageDiv); - }); -</script> -{% endblock %} -{% block title %} -{{ experiment.status_line }} -{% endblock %} -{% block page %} -{{block.super}} -<h3>{{experiment}}</h3> -<span>You are logged in as {{request.user.experimenter}}.</span> -<hr/> -<div id='experimenter-sidebar'> - <h5>Activity Log</h5> - <div id='experiment-messages' class='experimenter-sidebar-messages notice ui-corner-all'> - {% for group in experiment.groups.all %} - {% for activity_log in group.current_round_activity_log %} - <div style='font-size: 0.75em; line-height: 1.0em;padding:3px;' class='ui-state-highlight'> - {{activity_log}} - </div> - {% endfor %} - {% endfor %} - </div> -</div> -<fieldset class='small ui-corner-all'> - <legend>Experiment management</legend> - <ul class='actions'> - <li><span id='refreshAllParticipants' title='Sends a page refresh to all connected participants.' class='clickable' > - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_refresh.png);'></span> - refresh all participants</span> - </li> - <li><span id='gotoUrl' title='Moves all connected participants from waiting page to active page.' class='clickable' > - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_right.png);'></span> - transition all participants to next round</span> - </li> - <li> - <a href='download/csv'> - <span class='vcweb-icon ui-icon icon-left' style='margin: 8px 0.15em 0px 0px; background:url(/static/images/download-icon.png);'></span> - download data as <img src='/static/images/famfamfam/page_white_text.png' style='margin: 5px 0 0 0;' alt='' /> csv - </a> | - <a href='download/xls'><img src='/static/images/famfamfam/page_white_excel.png' style='margin: 5px 0 0 0;' alt=''/> xls</a> - </li> - </ul> -</fieldset> -<div class='experiment-dashboard'> - {% comment %} - FIXME: Improve this so that we can just inject a new round_configuration - JSON object in and everything auto-updates. - {% endcomment %} - <div id='statusSpinner' style='display:none;'> - <img src='/static/images/squares-circle-ajax-loader.gif' alt='... working ...' /> - </div> - <div id='statusDiv'> - {% block status %} - {% with participant_count=experiment.participants.count %} - <fieldset class='small ui-corner-all'> - <legend>round status</legend> - <ul id='actions' class='actions'> - {% if experiment.is_active %} - {% if experiment.is_round_in_progress %} - <li><a class='confirm-experiment-action' name='end_round' href='end-round' title='Stops the current round.'> - <span class='vcweb-icon icon-left ui-icon' style='background: url(/static/images/famfamfam/control_stop_blue.png);' ></span>end round</a></li> - {% else %} - <li><a class='confirm-experiment-action' name='start_round' href='start-round' title='Starts the round.'> - <span class='ui-icon vcweb-icon icon-left' style='background:url(/static/images/famfamfam/control_play_blue.png);' ></span>start round</a></li> - {% endif %} - <li><a class='confirm-experiment-action' name='advance_to_next_round' href='advance-to-next-round' title='Stops the current round if necessary and advances to the next round.'> - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/control_fastforward_blue.png);' ></span>advance to next round</a></li> - {% else %} - {% if participant_count == 0 %} - <div class='alert alertIcon ui-corner-all'> - There are no registered participants. Please <a href='{% url core:dashboard %}'>return to the dashboard to register participants.</a> - </div> - {% else %} - <li><a title='You must first activate an experiment before you can run it.' class='confirm-experiment-action' name='activate' - href='activate'><span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' ></span>activate</a> - </li> - {%endif%} - {% endif %} - </ul> - <br/> - <ul class='messages'> - <li title='{{experiment.actions_help_text}}'>{{ experiment.round_status_display }}</li> - <li>Type: {{ experiment.current_round.get_round_type_display }}</li> - <li>Round started on {{ experiment.current_round_start_time }}</li> - <li>Time remaining: {{ experiment.time_remaining }}</li> - <li>Registered participants: <b>{{participant_count}}</b> - </li> - </ul> - </fieldset> - {% endwith %} - {% endblock status %} - </div> -</div> -<div id='experimentData'> - {% block data %} - {% for round_data in experiment.round_data.all %} - <h3><a href='#'>{{ round_data }}</a></h3> - <div id='round_data_{{forloop.counter}}'> - {% if round_data.group_data_values.count > 0 %} - <h4 class='collapsible'>Group data</h4> - <table> - <thead> - <tr><th>Group</th><th>Parameter Name</th><th>Value</th></tr> - </thead> - <tbody> - {% for group_data_value in round_data.group_data_values.all %} - <tr> - <td> - <a class='tooltip' title='{{ group_data_value.group.all_participants_str }}'> - {{ group_data_value.group }} - </a> - </td> - <td>{{ group_data_value.parameter.label}}</td> - <td>{{ group_data_value.value}}</td> - </tr> - {% endfor %} - </tbody> - </table> - {% else %} - <div class='info ui-corner-all'> - <span class='ui-icon ui-icon-info icon-left'></span>No group data for this round. - </div> - {% endif %} - {% comment %} participant data values {% endcomment %} - {% if round_data.participant_data_values.count > 0 %} - <h4>Participant data</h4> - <table> - <thead> - <tr><th>Participant</th><th>Parameter name</th><th>Value</th><th>Type</th></tr> - </thead> - <tbody> - {% for participant_data_value in round_data.participant_data_values.all %} - <tr> - <td> - <a class='tooltip' title='{{participant_data_value.participant}}'> - {{ participant_data_value.participant_number }} ({{ participant_data_value.group }}) - </a> - </td> - <td>{{ participant_data_value.parameter.label }}</td> - <td id='participant_data_value_{{participant_data_value.pk}}'>{{ participant_data_value.value }}</td> - <td>{{ participant_data_value.parameter.type }}</td> - </tr> - {% endfor %} - </tbody> - </table> - {% else %} - <div class='info ui-corner-all'><span class='ui-icon ui-icon-info icon-left'></span>No participant data for this round.</div> - {% endif %} - {% comment %} participant chats {% endcomment %} - {% if round_data.chat_messages.count > 0 %} - <h4 class='collapsible'>Chat data (click to hide)</h4> - <div id='chat_{{round_data.pk}}' class='chat notice ui-corner-all'> - {% for chat_message in round_data.chat_messages.all %} - <div class='ui-state-highlight'> - <a class='tooltip' name='{{chat_message.pk}}' title='{{chat_message.date_created}} {{chat_message.participant}}'> - {{chat_message.date_created|date:"H:s"}}</a> | {{chat_message}} - <span class='ui-icon ui-icon-comment icon-right'></span> - </div> - {% endfor %} - </div> - {% endif %} - </div> - {% empty %} - <div class='alert ui-state-highlight ui-corner-all'><span class='ui-icon ui-icon-alert icon-left'></span>Round data is not yet available.</div> - {% endfor %} - {% endblock data %} -</div> -{% endblock page %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/participant-dashboard.html --- a/vcweb/core/templates/participant-dashboard.html Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -{% extends "base-participant.html" %} - -{% block participant_socket_io %} -{% endblock %} -{% block head %} -{{block.super}} -<script type='text/javascript'> - $(function() { - $('[title]').qtip({position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'green', tip: 'bottomMiddle'} }); - }); -</script> -{% endblock %} - -{% block title %} -Virtual Commons Web Participant Dashboard -{% endblock %} - -{% block page %} -<div class='info infoIcon ui-corner-all'> - Welcome back, {{request.user.participant}}. Experiments you're participating in are listed below. -</div> - -<div id='experiments'> -{% for experiment_metadata, experiment_status_dict in experiments.items %} -<h3> {{ experiment_metadata.title }} </h3> -{% for experiment_status, experiments in experiment_status_dict.items %} -{% if experiments %} -<h4>{{experiments.0.get_status_display}}</h4> -{% for experiment in experiments %} -<div style='padding: 10px;' class='ui-state-highlight'> - <a title='This experiment is being run by {{experiment.experimenter}}' href='{{ experiment.participant_url }}'><span class='icon-left ui-icon {{experiment_status|lower}}'></span>{{ experiment.status_line }}, started {{experiment.current_round_start_time}}</a> -</div> -{% endfor %} -{% endif %} -{% endfor %} -{% endfor %} -</div> -{% endblock page %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/participant/base.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/participant/base.html Mon Apr 04 14:13:08 2011 -0700 @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block head %} + {{block.super}} + {% block participant_socket_io %} + <script type='text/javascript' src='/static/js/jquery.validate.min.js'></script> + {% include "includes/participant.events.html" %} + {% include "includes/socket.io.html" %} + <script type='text/javascript'> + connect(window.location.hostname, 8888, 'participant/{{participant_experiment_relationship.pk}}'); + </script> + {% endblock %} +{% endblock %} + +{% block title %} + Virtual Commons Web Participant Interface +{% endblock %} + +{% block header %} + {% include "includes/participant-nav-menu.html" %} +{% endblock %} + + + diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/templates/participant/dashboard.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/participant/dashboard.html Mon Apr 04 14:13:08 2011 -0700 @@ -0,0 +1,38 @@ +{% extends "participant/base.html" %} + +{% block participant_socket_io %} +{% endblock %} +{% block head %} +{{block.super}} +<script type='text/javascript'> + $(function() { + $('[title]').qtip({position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'green', tip: 'bottomMiddle'} }); + }); +</script> +{% endblock %} + +{% block title %} +Virtual Commons Web Participant Dashboard +{% endblock %} + +{% block page %} +<div class='info infoIcon ui-corner-all'> + Welcome back, {{request.user.participant}}. Experiments you're participating in are listed below. +</div> + +<div id='experiments'> +{% for experiment_metadata, experiment_status_dict in experiments.items %} +<h3> {{ experiment_metadata.title }} </h3> +{% for experiment_status, experiments in experiment_status_dict.items %} +{% if experiments %} +<h4>{{experiments.0.get_status_display}}</h4> +{% for experiment in experiments %} +<div style='padding: 10px;' class='ui-state-highlight'> + <a title='This experiment is being run by {{experiment.experimenter}}' href='{{ experiment.participant_url }}'><span class='icon-left ui-icon {{experiment_status|lower}}'></span>{{ experiment.status_line }}, started {{experiment.current_round_start_time}}</a> +</div> +{% endfor %} +{% endif %} +{% endfor %} +{% endfor %} +</div> +{% endblock page %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/urls.py --- a/vcweb/core/urls.py Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/core/urls.py Mon Apr 04 14:13:08 2011 -0700 @@ -1,6 +1,6 @@ from django.conf.urls.defaults import patterns, url from django.contrib.auth.decorators import login_required -from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, ConfigureExperimentView +from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, ConfigureExperimentView, CloneExperimentView ''' URLs defined by the core vcweb app. ''' @@ -14,9 +14,9 @@ url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/(?P<pk>\d+)/monitor$', MonitorExperimentView.as_view(), name='monitor_experiment'), url(r'^experiment/(?P<pk>\d+)/configure$', ConfigureExperimentView.as_view(), name='configure_experiment'), - url(r'^experiment/(?P<pk>\d+)/clone$', 'clone', name='clone'), - url(r'^experiment/(?P<pk>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), - url(r'^experiment/(?P<pk>\d+)/clear-participants', 'clear_participants', name='clear_participants'), + url(r'^experiment/(?P<pk>\d+)/clone$', CloneExperimentView.as_view(), name='clone'), +# url(r'^experiment/(?P<pk>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), +# url(r'^experiment/(?P<pk>\d+)/clear-participants', 'clear_participants', name='clear_participants'), url(r'^experiment/(?P<pk>\d+)/download/(?P<file_type>[\w]+)$', 'download_data', name='download_data'), # experiment controller actions are the most general, needs to be matched at the very end url(r'^experiment/(?P<pk>\d+)/(?P<experiment_action>[\w-]+)$', 'experiment_controller', name='experiment_controller'), diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/core/views.py --- a/vcweb/core/views.py Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/core/views.py Mon Apr 04 14:13:08 2011 -0700 @@ -9,7 +9,7 @@ from django.views.generic import ListView, FormView, TemplateView from django.views.generic.base import TemplateResponseMixin from django.views.generic.detail import SingleObjectMixin -from vcweb.core.forms import RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm +from vcweb.core.forms import RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm, ConfigureExperimentForm from vcweb.core.models import Participant, Experiment, Institution, is_participant, is_experimenter from vcweb.core.decorators import anonymous_required, experimenter_required, participant_required import hashlib @@ -32,9 +32,9 @@ def get_template_names(self): user = self.request.user if is_experimenter(user): - return ['experimenter-dashboard.html'] + return ['experimenter/dashboard.html'] else: - return ['participant-dashboard.html'] + return ['participant/dashboard.html'] def get_queryset(self): user = self.request.user if is_experimenter(user): @@ -141,6 +141,8 @@ def process_experiment(self, experiment): pass + def check_user(self, user, experiment): + pass def get(self, request, **kwargs): try: @@ -156,38 +158,60 @@ def get_object(self, queryset=None): pk = self.kwargs.get('pk', None) experiment = Experiment.objects.get(pk=pk) + user = self.request.user + return self.check_user(user, experiment) + +class ParticipantSingleExperimentMixin(SingleExperimentMixin, ParticipantMixin): + def check_user(self, user, experiment): + # FIXME: should we do a user.participant in experiment.participants.all() check? + pass + +class ExperimenterSingleExperimentMixin(SingleExperimentMixin, ExperimenterMixin): + def check_user(self, user, experiment): if self.request.user.experimenter.pk == experiment.experimenter.pk: return experiment raise Experiment.DoesNotExist("You do not have access to %s" % experiment) -class MonitorExperimentView(ExperimenterMixin, SingleExperimentMixin, TemplateView): - template_name = 'monitor.html' +class MonitorExperimentView(ExperimenterSingleExperimentMixin, TemplateView): + template_name = 'experimenter/monitor.html' -class ConfigureExperimentView(ExperimenterMixin, SingleExperimentMixin, FormView): +class ConfigureExperimentView(ExperimenterSingleExperimentMixin, FormView): form_class = ConfigureExperimentForm - template_name = 'configure.html' + template_name = 'experimenter/register-participants.html' def form_valid(self, form): request = self.request -def _get_experiment(self, request, experiment_id): - experiment = Experiment.objects.get(pk=experiment_id) - if request.user.experimenter.pk == experiment.experimenter.pk: - return experiment - raise Experiment.DoesNotExist("Sorry, you do not appear to have access to %s" % experiment) + @experimenter_required + def add_participants(request, pk=None, count=0): + try: + experiment = _get_experiment(request, pk) + count = int(count) + if count > 0: + experiment.setup_test_participants(count=count) + except Experiment.DoesNotExist: + error_message = "Tried to monitor non-existent experiment (id %s)" % pk + logger.warning(error_message) + messages.warning(request, error_message) + return redirect('core:dashboard') -@experimenter_required -def clone(request, pk=None, count=0): - try: - experiment = _get_experiment(request, pk) - cloned_experiment = experiment.clone() - if count > 0: - cloned_experiment.setup_test_participants(count=count) - logger.debug("cloned experiment: %s" % cloned_experiment) - except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % pk - logger.warning(error_message) - messages.warning(request, error_message) - return redirect('core:dashboard') + @experimenter_required + def clear_participants(request, pk=None): + try: + experiment = _get_experiment(request, pk) + if experiment.participants.count() > 0: + experiment.participants.all().delete() + except Experiment.DoesNotExist: + error_message = "Tried to monitor non-existent experiment (id %s)" % pk + logger.warning(error_message) + messages.warning(request, error_message) + return redirect('core:dashboard') + +# FIXME: uses GET (which should be idempotent) to modify database state which makes HTTP sadful +class CloneExperimentView(ExperimenterSingleExperimentMixin, TemplateView): + def process_experiment(self, experiment): + return experiment.clone() + def render_to_response(self, context): + return redirect('core:dashboard') @experimenter_required def manage(request, pk=None): @@ -199,31 +223,6 @@ logger.warning("Tried to manage non-existent experiment with id %s" % pk) -@experimenter_required -def add_participants(request, pk=None, count=0): - try: - experiment = _get_experiment(request, pk) - count = int(count) - if count > 0: - experiment.setup_test_participants(count=count) - except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % pk - logger.warning(error_message) - messages.warning(request, error_message) - return redirect('core:dashboard') - -@experimenter_required -def clear_participants(request, pk=None): - try: - experiment = _get_experiment(request, pk) - if experiment.participants.count() > 0: - experiment.participants.all().delete() - except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % pk - logger.warning(error_message) - messages.warning(request, error_message) - return redirect('core:dashboard') - # FIXME: add data converter objects to write to csv, excel, etc. @experimenter_required diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/chat.html --- a/vcweb/forestry/templates/forestry/chat.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/chat.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-participant.html" %} +{% extends "participant/base.html" %} {% block head %} {{ block.super }} <script type="text/javascript"> diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/experimenter-index.html --- a/vcweb/forestry/templates/forestry/experimenter-index.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/experimenter-index.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-experimenter.html" %} +{% extends "experimenter/base.html" %} {% block title %} Forestry Experimenter Interface {% endblock %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/instructions.html --- a/vcweb/forestry/templates/forestry/instructions.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/instructions.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-participant.html" %} +{% extends "participant/base.html" %} {% block head %} {{ block.super }} {% include "includes/participant.events.html" %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/manage-experiment.html --- a/vcweb/forestry/templates/forestry/manage-experiment.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/manage-experiment.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-experimenter.html" %} +{% extends "experimenter/base.html" %} {% block title %} Forestry Experiment Management Interface {% endblock %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/participant-index.html --- a/vcweb/forestry/templates/forestry/participant-index.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participant-index.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,10 +1,10 @@ -{% extends "base-participant.html" %} +{% extends "participant/base.html" %} -{% block title %}Forestry{% endblock %} +{% block title %}VCWEB Forestry Experiment{% endblock %} {% block page %} <div class='info'> - Welcome back, {{ user.participant }}. + Welcome back, {{ request.user.participant }}. </div> <h3>{{experiment.namespace|title}} Experiments</h3> <div class='notice'> diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-participant.html" %} +{% extends "participant/base.html" %} {% block head %} {{ block.super }} <script type="text/javascript"> diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/quiz.html --- a/vcweb/forestry/templates/forestry/quiz.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/quiz.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-participant.html" %} +{% extends "participant/base.html" %} {% block title %} Forestry Quiz Round {% endblock %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/templates/forestry/wait.html --- a/vcweb/forestry/templates/forestry/wait.html Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/templates/forestry/wait.html Mon Apr 04 14:13:08 2011 -0700 @@ -1,4 +1,4 @@ -{% extends "base-participant.html" %} +{% extends "participant/base.html" %} {% block head %} {{ block.super }} {% include "includes/participant.events.html" %} diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/forestry/views.py --- a/vcweb/forestry/views.py Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/forestry/views.py Mon Apr 04 14:13:08 2011 -0700 @@ -4,9 +4,12 @@ from django.http import Http404 from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext +from django.views.generic import View +from django.views.generic.detail import SingleObjectTemplateResponseMixin, SingleObjectMixin +from vcweb.core.decorators import participant_required, experimenter_required from vcweb.core.forms import QuizForm from vcweb.core.models import is_participant, is_experimenter, Experiment -from vcweb.core.decorators import participant_required, experimenter_required +from vcweb.core.views import ParticipantSingleExperimentMixin from vcweb.forestry.models import get_resource_level, get_max_harvest_decision, get_forestry_experiment_metadata, set_harvest_decision, get_harvest_decision, get_group_harvest, get_regrowth from vcweb.forestry.forms import HarvestDecisionForm import logging @@ -106,6 +109,10 @@ logger.warning("No experiment found with id %s" % experiment_id) return redirect('forestry:participant_index') + +class ParticipateView(SingleObjectTemplateResponseMixin, ParticipantSingleExperimentMixin, View): + template_name_field = 'current_round_template' + # FIXME: refactor this ugliness @participant_required def participate(request, experiment_id=None): diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Fri Apr 01 14:23:46 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Mon Apr 04 14:13:08 2011 -0700 @@ -1,5 +1,4 @@ #!/usr/bin/env python - import tornado.web from tornadio import SocketConnection, get_router, server import os @@ -45,7 +44,7 @@ # (participant.pk, experiment.pk) -> connection connection_to_participant = {} participant_to_connection = {} - +# experimenter maps connection_to_experimenter = {} # (experimenter.pk, experiment.pk) -> connection experimenter_to_connection = {} @@ -55,8 +54,7 @@ def add_experimenter(self, connection, incoming_experimenter_pk, incoming_experiment_pk): experimenter_pk = int(incoming_experimenter_pk) experiment_id = int(incoming_experiment_pk) - logger.debug("registering experimenter %s with connection %s" % - (experimenter_pk, connection)) + logger.debug("registering experimenter %s with connection %s" % (experimenter_pk, connection)) if connection in self.connection_to_experimenter: self.remove_experimenter(connection) self.connection_to_experimenter[connection] = (experimenter_pk, experiment_id) diff -r 3d768c41bfa6 -r 530087acf7e7 vcweb/vcweb-tornado.py --- a/vcweb/vcweb-tornado.py Fri Apr 01 14:23:46 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -#!/usr/bin/env python - -import tornado.web -from tornad_io import SocketIOHandler -from tornad_io import SocketIOServer - -import os -import sys -import logging - -logger = logging.getLogger(__name__) - -sys.path.append(os.path.abspath('..')) - -os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' - -from vcweb.core.models import ParticipantGroupRelationship, ChatMessage, Experiment - -''' -store mappings between beaker session ids and ParticipantGroupRelationship pks -''' -class SessionManager: - ''' associates beaker session ids with ParticipantGroupRelationship.pks ''' - session_id_to_participant = {} - ''' the reverse mapping, associates ParticipantGroupRelationship.pks with the beaker session ''' - pgr_to_session = {} - - def get_participant(self, session): - logger.debug("trying to retrieve participant group relationship for session id %s" % session) - logger.debug("maps are %s and %s" % (self.session_id_to_participant, self.pgr_to_session)) - return ParticipantGroupRelationship.objects.get(pk=self.session_id_to_participant[session.id]) - - def add(self, session, participant_group_relationship): - if participant_group_relationship.pk in self.pgr_to_session: - logger.debug("participant already has a session, removing previous mappings.") - self.remove(self.pgr_to_session[participant_group_relationship.pk]) - - self.session_id_to_participant[session.id] = participant_group_relationship.pk - self.pgr_to_session[participant_group_relationship.pk] = session - - def remove(self, session): - try: - participant_group_pk = self.session_id_to_participant[session.id] - del self.pgr_to_session[participant_group_pk] - del ... [truncated message content] |
From: <vir...@li...> - 2011-04-01 21:21:53
|
Subject: hg.virtualcommons 317 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/3d768c41bfa6 changeset: 317:3d768c41bfa6 user: Allen Lee <all...@as...> date: Fri Apr 01 14:23:46 2011 -0700 description: cleaning up views some more, starting to work out basic form-based experiment configuration. diffstat: vcweb/core/ajax.py | 10 +- vcweb/core/forms.py | 25 +++++++- vcweb/core/urls.py | 23 ++++--- vcweb/core/views.py | 137 ++++++++++++++++++++++++--------------------- vcweb/static/css/style.css | 6 +- 5 files changed, 116 insertions(+), 85 deletions(-) diffs (397 lines): diff -r f510ec49584f -r 3d768c41bfa6 vcweb/core/ajax.py --- a/vcweb/core/ajax.py Thu Mar 31 17:38:34 2011 -0700 +++ b/vcweb/core/ajax.py Fri Apr 01 14:23:46 2011 -0700 @@ -74,11 +74,11 @@ t.render(c) return HttpResponse(render_template_block(t, block, c), mimetype=mimetype) -def _get_experiment(request, experiment_id): - experiment = Experiment.objects.get(pk=experiment_id) +def _get_experiment(request, pk): + experiment = Experiment.objects.get(pk=pk) if request.user.experimenter == experiment.experimenter: return experiment - raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, experiment_id)) + raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, pk)) def _render_experiment_monitor_block(block, experiment, request): return render_block_to_string('monitor.html', block, { 'experiment': experiment }, @@ -86,9 +86,9 @@ @experimenter_required @dajaxice_register -def experiment_controller(request, experiment_id, action=''): +def experiment_controller(request, pk, action=''): try: - experiment = _get_experiment(request, experiment_id) + experiment = _get_experiment(request, pk) experiment_func = getattr(experiment, action.replace('-', '_'), None) if experiment_func: experiment_func() diff -r f510ec49584f -r 3d768c41bfa6 vcweb/core/forms.py --- a/vcweb/core/forms.py Thu Mar 31 17:38:34 2011 -0700 +++ b/vcweb/core/forms.py Fri Apr 01 14:23:46 2011 -0700 @@ -1,11 +1,15 @@ from django import forms from django.contrib.auth import authenticate from django.contrib.auth.models import User -from django.forms import widgets +from django.forms import widgets, ValidationError from django.utils.translation import ugettext_lazy as _ from vcweb.core.models import Participant, Experimenter +from django.core.validators import email_re + +import re + REQUIRED_EMAIL_ATTRIBUTES = { 'class' : 'required email' } REQUIRED_ATTRIBUTES = { 'class' : 'required' } @@ -25,7 +29,6 @@ return email raise forms.ValidationError(_("This email address is already in our system.")) - def clean_confirm_password(self): password = self.cleaned_data['password'] confirm_password = self.cleaned_data['confirm_password'] @@ -33,7 +36,6 @@ raise forms.ValidationError(_("Please make sure your passwords match.")) return self.confirm_password - class LoginForm(forms.Form): email = forms.EmailField(widget=widgets.TextInput(attrs=REQUIRED_EMAIL_ATTRIBUTES)) password = forms.CharField(widget=widgets.PasswordInput(attrs=REQUIRED_ATTRIBUTES)) @@ -61,6 +63,23 @@ class Meta: model = Experimenter +email_separator_re = re.compile(r'[^\w\.\-\+@_]+') +class EmailListField(forms.CharField): + widget = forms.Textarea + def clean(self, value): + super(EmailListField, self).clean(value) + emails = email_separator_re.split(value) + if not emails: + raise ValidationError(_(u'You must enter at least one email address.')) + for email in emails: + if not email_re.match(email): + raise ValidationError(_(u'%s is not a valid email address.' % email)) + return emails + +class ConfigureExperimentForm(forms.Form): + clone_experiment = forms.NullBooleanField(label="Clone this experiment?") + registered_participants = EmailListField(label="Registered participants") + class QuizForm(forms.Form): name_question = forms.CharField(max_length=64, label="What is your name?") def __init__(self, *args, **kwargs): diff -r f510ec49584f -r 3d768c41bfa6 vcweb/core/urls.py --- a/vcweb/core/urls.py Thu Mar 31 17:38:34 2011 -0700 +++ b/vcweb/core/urls.py Fri Apr 01 14:23:46 2011 -0700 @@ -1,26 +1,27 @@ from django.conf.urls.defaults import patterns, url -from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView +from django.contrib.auth.decorators import login_required +from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView, MonitorExperimentView, ConfigureExperimentView ''' URLs defined by the core vcweb app. ''' urlpatterns = patterns('vcweb.core.views', - url(r'^dashboard/?$', Dashboard.as_view(), name='dashboard'), + url(r'^dashboard/?$', login_required(Dashboard.as_view()), name='dashboard'), url(r'^accounts/login/$', LoginView.as_view(), name='login'), url(r'^accounts/logout/$', LogoutView.as_view(), name='logout'), url(r'^accounts/register/$', RegistrationView.as_view(), name='register'), url(r'^accounts/profile/$', 'account_profile', name='profile'), - url(r'^participate/(?P<experiment_id>\d+)/instructions', 'instructions', name='instructions'), + url(r'^participate/(?P<pk>\d+)/instructions', 'instructions', name='instructions'), url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), - url(r'^experiment/(?P<experiment_id>\d+)/monitor$', 'monitor', name='monitor_experiment'), - url(r'^experiment/(?P<experiment_id>\d+)/configure$', 'configure', name='configure_experiment'), - url(r'^experiment/(?P<experiment_id>\d+)/clone$', 'clone', name='clone'), - url(r'^experiment/(?P<experiment_id>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), - url(r'^experiment/(?P<experiment_id>\d+)/clear-participants', 'clear_participants', name='clear_participants'), - url(r'^experiment/(?P<experiment_id>\d+)/download/(?P<file_type>[\w]+)$', 'download_data', name='download_data'), + url(r'^experiment/(?P<pk>\d+)/monitor$', MonitorExperimentView.as_view(), name='monitor_experiment'), + url(r'^experiment/(?P<pk>\d+)/configure$', ConfigureExperimentView.as_view(), name='configure_experiment'), + url(r'^experiment/(?P<pk>\d+)/clone$', 'clone', name='clone'), + url(r'^experiment/(?P<pk>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), + url(r'^experiment/(?P<pk>\d+)/clear-participants', 'clear_participants', name='clear_participants'), + url(r'^experiment/(?P<pk>\d+)/download/(?P<file_type>[\w]+)$', 'download_data', name='download_data'), # experiment controller actions are the most general, needs to be matched at the very end - url(r'^experiment/(?P<experiment_id>\d+)/(?P<experiment_action>[\w-]+)$', 'experiment_controller', name='experiment_controller'), + url(r'^experiment/(?P<pk>\d+)/(?P<experiment_action>[\w-]+)$', 'experiment_controller', name='experiment_controller'), ) # add ajax actions urlpatterns += patterns('vcweb.core.ajax', - url(r'^ajax/(?P<experiment_id>\d+)/(<?P<experiment_action[\w-]+)$', 'experiment_controller'), + url(r'^ajax/(?P<pk>\d+)/(<?P<experiment_action[\w-]+)$', 'experiment_controller'), ) diff -r f510ec49584f -r 3d768c41bfa6 vcweb/core/views.py --- a/vcweb/core/views.py Thu Mar 31 17:38:34 2011 -0700 +++ b/vcweb/core/views.py Fri Apr 01 14:23:46 2011 -0700 @@ -8,6 +8,7 @@ from django.utils.decorators import method_decorator from django.views.generic import ListView, FormView, TemplateView from django.views.generic.base import TemplateResponseMixin +from django.views.generic.detail import SingleObjectMixin from vcweb.core.forms import RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm from vcweb.core.models import Participant, Experiment, Institution, is_participant, is_experimenter from vcweb.core.decorators import anonymous_required, experimenter_required, participant_required @@ -21,12 +22,6 @@ """ account registration / login / logout / profile views """ -def _get_experiment(request, experiment_id): - experiment = Experiment.objects.get(pk=experiment_id) - if request.user.experimenter == experiment.experimenter: - return experiment - raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, experiment_id)) - class AnonymousMixin(object): @method_decorator(anonymous_required) def dispatch(self, *args, **kwargs): @@ -117,14 +112,14 @@ return super(ParticipantMixin, self).dispatch(*args, **kwargs) @login_required -def instructions(request, experiment_id=None, namespace=None): - if experiment_id: - experiment = Experiment.objects.get(pk=experiment_id) +def instructions(request, pk=None, namespace=None): + if pk: + experiment = Experiment.objects.get(pk=pk) elif namespace: experiment = Experiment.objects.get(experiment_metadata__namespace=namespace) if not experiment: - logger.warning("Tried to request instructions for id %s or namespace %s" % (experiment_id, namespace)) + logger.warning("Tried to request instructions for id %s or namespace %s" % (pk, namespace)) return redirect('home') return render_to_response(experiment.get_template_path('instructions.html'), locals(), context_instance=RequestContext(request)) @@ -136,91 +131,105 @@ these. """ class ExperimenterMixin(object): - def _get_experiment(self, request, experiment_id): - experiment = Experiment.objects.get(pk=experiment_id) - if request.user.experimenter.pk == experiment.experimenter.pk: - return experiment - raise Experiment.DoesNotExist("Sorry, you do not appear to have access to %s" % experiment) - @method_decorator(experimenter_required) def dispatch(self, *args, **kwargs): return super(ExperimenterMixin, self).dispatch(*args, **kwargs) +class SingleExperimentMixin(SingleObjectMixin): + model = Experiment + context_object_name = 'experiment' + + def process_experiment(self, experiment): + pass + + def get(self, request, **kwargs): + try: + self.object = self.get_object() + self.process_experiment(self.object) + context = self.get_context_data(object=self.object) + return self.render_to_response(context) + except Experiment.DoesNotExist as e: + logger.warning(e) + messages.warning(request, e) + return redirect( reverse('core:dashboard') ) + + def get_object(self, queryset=None): + pk = self.kwargs.get('pk', None) + experiment = Experiment.objects.get(pk=pk) + if self.request.user.experimenter.pk == experiment.experimenter.pk: + return experiment + raise Experiment.DoesNotExist("You do not have access to %s" % experiment) + +class MonitorExperimentView(ExperimenterMixin, SingleExperimentMixin, TemplateView): + template_name = 'monitor.html' + +class ConfigureExperimentView(ExperimenterMixin, SingleExperimentMixin, FormView): + form_class = ConfigureExperimentForm + template_name = 'configure.html' + def form_valid(self, form): + request = self.request + +def _get_experiment(self, request, experiment_id): + experiment = Experiment.objects.get(pk=experiment_id) + if request.user.experimenter.pk == experiment.experimenter.pk: + return experiment + raise Experiment.DoesNotExist("Sorry, you do not appear to have access to %s" % experiment) @experimenter_required -def configure(request, experiment_id=None): - # lookup game instance id (or create a new one?) - experiment = Experiment.objects.get(pk=experiment_id) - return render_to_response('configure.html', locals(), context_instance=RequestContext(request)) - -@experimenter_required -def manage(request, experiment_id=None): - try : - experiment = Experiment.objects.get(pk=experiment_id) -# redirect to experiment specific management page? - return redirect(experiment.management_url) - except Experiment.DoesNotExist: - logger.warning("Tried to manage non-existent experiment with id %s" % - experiment_id) - -@experimenter_required -def clone(request, experiment_id=None, count=0): +def clone(request, pk=None, count=0): try: - experiment = _get_experiment(request, experiment_id) + experiment = _get_experiment(request, pk) cloned_experiment = experiment.clone() if count > 0: cloned_experiment.setup_test_participants(count=count) logger.debug("cloned experiment: %s" % cloned_experiment) except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id + error_message = "Tried to monitor non-existent experiment (id %s)" % pk logger.warning(error_message) messages.warning(request, error_message) return redirect('core:dashboard') @experimenter_required -def add_participants(request, experiment_id=None, count=0): +def manage(request, pk=None): + try : + experiment = Experiment.objects.get(pk=pk) +# redirect to experiment specific management page? + return redirect(experiment.management_url) + except Experiment.DoesNotExist: + logger.warning("Tried to manage non-existent experiment with id %s" % + pk) + +@experimenter_required +def add_participants(request, pk=None, count=0): try: - experiment = _get_experiment(request, experiment_id) + experiment = _get_experiment(request, pk) count = int(count) if count > 0: experiment.setup_test_participants(count=count) except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id + error_message = "Tried to monitor non-existent experiment (id %s)" % pk logger.warning(error_message) messages.warning(request, error_message) return redirect('core:dashboard') @experimenter_required -def clear_participants(request, experiment_id=None): +def clear_participants(request, pk=None): try: - experiment = _get_experiment(request, experiment_id) + experiment = _get_experiment(request, pk) if experiment.participants.count() > 0: experiment.participants.all().delete() except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id + error_message = "Tried to monitor non-existent experiment (id %s)" % pk logger.warning(error_message) messages.warning(request, error_message) return redirect('core:dashboard') -@experimenter_required -def monitor(request, experiment_id=None): - try: - experiment = Experiment.objects.get(pk=experiment_id) - if request.user.experimenter.pk == experiment.experimenter.pk: - return render_to_response('monitor.html', locals(), context_instance=RequestContext(request)) -# redirect to experiment specific management page? - except Experiment.DoesNotExist: - error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id - logger.warning(error_message) - messages.warning(request, error_message) - return redirect('core:dashboard') - # FIXME: add data converter objects to write to csv, excel, etc. @experimenter_required -def download_data(request, experiment_id=None, file_type='csv'): +def download_data(request, pk=None, file_type='csv'): try: - experiment = Experiment.objects.get(pk=experiment_id) + experiment = Experiment.objects.get(pk=pk) response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = 'attachment; filename=%s' % experiment.data_file_name() writer = unicodecsv.UnicodeWriter(response) @@ -247,16 +256,16 @@ chat_message.date_created, round_configuration]) return response except Experiment.DoesNotExist as e: - error_message = "Tried to download non-existent experiment, id %s" % experiment_id + error_message = "Tried to download non-existent experiment, id %s" % pk logger.warning(error_message) messages.warning(request, error_message) return redirect('core:dashboard') @experimenter_required -def download_data_excel(request, experiment_id=None): +def download_data_excel(request, pk=None): import xlwt try: - experiment = Experiment.objects.get(pk=experiment_id) + experiment = Experiment.objects.get(pk=pk) response = HttpResponse(mimetype='application/vnd.ms-excel') response['Content-Disposition'] = 'attachment; filename=%s' % experiment.data_file_name(file_ext='xls') workbook = xlwt.Workbook() @@ -291,10 +300,10 @@ logger.warning(e) @experimenter_required -def experiment_controller(request, experiment_id=None, experiment_action=None): +def experiment_controller(request, pk=None, experiment_action=None): try: experimenter = request.user.experimenter - experiment = Experiment.objects.get(pk=experiment_id) + experiment = Experiment.objects.get(pk=pk) # TODO: provide experimenter access to other users besides the creator of the # experiment? if experimenter.pk == experiment.experimenter.pk: @@ -302,7 +311,7 @@ if experiment_func: # pass params? start_round() takes a sender for instance.. experiment_func() - return redirect('core:monitor_experiment', experiment_id=experiment_id) + return redirect('core:monitor_experiment', pk=pk) else: error_message = "Invalid experiment action: You ({experimenter}) tried to invoke {experiment_action} on {experiment}".format( experimenter=experimenter, experiment_action=experiment_action, experiment=experiment) @@ -311,8 +320,8 @@ experimenter=experimenter, experiment_action=experiment_action, experiment=experiment) except Experiment.DoesNotExist: - error_message = 'Could not invoke {experiment_action} on a non-existent experiment (id: {experiment_id}, experimenter: {experimenter})'.format( - experimenter=experimenter, experiment_action=experiment_action, experiment_id=experiment_id) + error_message = 'Could not invoke {experiment_action} on a non-existent experiment (id: {pk}, experimenter: {experimenter})'.format( + experimenter=experimenter, experiment_action=experiment_action, pk=pk) logger.warning(error_message) messages.warning(request, error_message) diff -r f510ec49584f -r 3d768c41bfa6 vcweb/static/css/style.css --- a/vcweb/static/css/style.css Thu Mar 31 17:38:34 2011 -0700 +++ b/vcweb/static/css/style.css Fri Apr 01 14:23:46 2011 -0700 @@ -136,9 +136,11 @@ text-transform: lowercase; padding: 2px 6px; } -.field > input { +.field > input[type='text'] { width: 15em; - +} +.field > input[type='password'] { + width: 15em; } #experimentData a { text-decoration: none; |
From: <vir...@li...> - 2011-04-01 00:36:58
|
Subject: hg.virtualcommons 316 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/f510ec49584f changeset: 316:f510ec49584f user: Allen Lee <all...@as...> date: Thu Mar 31 17:38:34 2011 -0700 description: adding auth token back into CommonsUser and converting registration form to class based views diffstat: vcweb/core/models.py | 2 +- vcweb/core/urls.py | 6 +- vcweb/core/views.py | 80 +++++++++++++++------------------------ vcweb/static/css/style.css | 4 ++ 4 files changed, 39 insertions(+), 53 deletions(-) diffs (149 lines): diff -r a5124f7b37f2 -r f510ec49584f vcweb/core/models.py --- a/vcweb/core/models.py Thu Mar 31 13:40:56 2011 -0700 +++ b/vcweb/core/models.py Thu Mar 31 17:38:34 2011 -0700 @@ -89,7 +89,7 @@ user = models.OneToOneField(User, related_name='%(class)s', verbose_name=u'Django User', unique=True) failed_password_attempts = models.PositiveIntegerField(default=0) institution = models.ForeignKey(Institution, null=True, blank=True) -# authentication_token = models.CharField(max_length=64, null=True, blank=True) + authentication_token = models.CharField(max_length=64, null=True, blank=True) @property def full_name(self): diff -r a5124f7b37f2 -r f510ec49584f vcweb/core/urls.py --- a/vcweb/core/urls.py Thu Mar 31 13:40:56 2011 -0700 +++ b/vcweb/core/urls.py Thu Mar 31 17:38:34 2011 -0700 @@ -1,13 +1,13 @@ from django.conf.urls.defaults import patterns, url -from vcweb.core.views import Dashboard, LoginView +from vcweb.core.views import Dashboard, LoginView, LogoutView, RegistrationView ''' URLs defined by the core vcweb app. ''' urlpatterns = patterns('vcweb.core.views', url(r'^dashboard/?$', Dashboard.as_view(), name='dashboard'), url(r'^accounts/login/$', LoginView.as_view(), name='login'), - url(r'^accounts/logout/$', 'logout', name='logout'), - url(r'^accounts/register/$', 'register', name='register'), + url(r'^accounts/logout/$', LogoutView.as_view(), name='logout'), + url(r'^accounts/register/$', RegistrationView.as_view(), name='register'), url(r'^accounts/profile/$', 'account_profile', name='profile'), url(r'^participate/(?P<experiment_id>\d+)/instructions', 'instructions', name='instructions'), url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), diff -r a5124f7b37f2 -r f510ec49584f vcweb/core/views.py --- a/vcweb/core/views.py Thu Mar 31 13:40:56 2011 -0700 +++ b/vcweb/core/views.py Thu Mar 31 17:38:34 2011 -0700 @@ -56,7 +56,6 @@ class LoginView(FormView, AnonymousMixin): form_class = LoginForm template_name = 'registration/login.html' - def form_valid(self, form): request = self.request user = form.user_cache @@ -65,60 +64,43 @@ sha1.update("%s%i%s" % (user.email, user.pk, datetime.now())) request.session['authentication_token'] = base64.urlsafe_b64encode(sha1.digest()) return super(LoginView, self).form_valid(form) - def get_success_url(self): return_url = self.request.GET.get('next') return return_url if return_url else reverse('core:dashboard') -@anonymous_required() -def login(request): - if request.method == 'POST': - form = LoginForm(request.POST) - if form.is_valid(): - cleaned_data = form.cleaned_data - email = cleaned_data['email'] - password = cleaned_data['password'] - user = auth.authenticate(username=email, password=password) - if user is None: - logger.debug("user " + email + " failed to authenticate.") - form.errors['password'] = form.error_class(['Your password is incorrect.']) - else: - return_url = request.GET.get('next') - auth.login(request, user) - sha1 = hashlib.sha1() - sha1.update("%s%i%s" % (email, user.pk, datetime.now())) - request.session['authentication_token'] = base64.urlsafe_b64encode(sha1.digest()) - return redirect( return_url if return_url else 'core:dashboard') - else: - form = LoginForm() - return render_to_response('registration/login.html', locals(), context_instance=RequestContext(request)) +class LogoutView(TemplateView): + def get(self, request, *args, **kwargs): + user = request.user + commons_user = None + if is_participant(user): + commons_user = user.participant + elif is_experimenter(user): + commons_user = user.experimenter + commons_user.authentication_token = None + commons_user.save() + auth.logout(request) + return redirect('home') -def logout(request): - auth.logout(request) - request.session['authentication_token'] = None - return redirect('home') +class RegistrationView(FormView, AnonymousMixin): + form_class = RegistrationForm + template_name = 'registration/register.html' + def form_valid(self, form): + email = form.cleaned_data['email'].lower() + password = form.cleaned_data['password'] + first_name = form.cleaned_data['first_name'] + last_name = form.cleaned_data['last_name'] + institution_string = form.cleaned_data['institution'] + institution, created = Institution.objects.get_or_create(name=institution_string) + user = User.objects.create_user(email, email, password) + user.first_name = first_name + user.last_name = last_name + user.save() + participant = Participant.objects.create(user=user, institution=institution) + logger.debug("Creating new participant: %s" % participant) + auth.login(self.request, auth.authenticate(username=email, password=password)) -def register(request): - if request.method == 'POST': - form = RegistrationForm(request.POST) - if form.is_valid(): - email = form.cleaned_data['email'].lower() - password = form.cleaned_data['password'] - first_name = form.cleaned_data['first_name'] - last_name = form.cleaned_data['last_name'] - institution_string = form.cleaned_data['institution'] - institution, created = Institution.objects.get_or_create(name=institution_string) - user = User.objects.create_user(email, email, password) - user.first_name = first_name - user.last_name = last_name - user.save() - participant = Participant.objects.create(user=user, institution=institution) - logger.debug("Creating new participant: %s" % participant) - auth.login(request, auth.authenticate(username=email, password=password)) - return redirect('core:dashboard') - else: - form = RegistrationForm() - return render_to_response('registration/register.html', { 'form': form }, context_instance=RequestContext(request)) + def get_success_url(self): + return reverse('core:dashboard') @login_required def account_profile(request): diff -r a5124f7b37f2 -r f510ec49584f vcweb/static/css/style.css --- a/vcweb/static/css/style.css Thu Mar 31 13:40:56 2011 -0700 +++ b/vcweb/static/css/style.css Thu Mar 31 17:38:34 2011 -0700 @@ -136,6 +136,10 @@ text-transform: lowercase; padding: 2px 6px; } +.field > input { + width: 15em; + +} #experimentData a { text-decoration: none; } |
From: <vir...@li...> - 2011-03-31 20:42:16
|
Subject: hg.virtualcommons 315 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/a5124f7b37f2 changeset: 315:a5124f7b37f2 user: Allen Lee <all...@as...> date: Thu Mar 31 13:40:56 2011 -0700 description: converted login to LoginView diffstat: vcweb/core/forms.py | 12 ++++++ vcweb/core/urls.py | 4 +- vcweb/core/views.py | 88 +++++++++++++++++++++---------------------- 3 files changed, 57 insertions(+), 47 deletions(-) diffs (187 lines): diff -r 7784d52a6bd2 -r a5124f7b37f2 vcweb/core/forms.py --- a/vcweb/core/forms.py Thu Mar 31 12:57:25 2011 -0700 +++ b/vcweb/core/forms.py Thu Mar 31 13:40:56 2011 -0700 @@ -1,4 +1,5 @@ from django import forms +from django.contrib.auth import authenticate from django.contrib.auth.models import User from django.forms import widgets from django.utils.translation import ugettext_lazy as _ @@ -37,6 +38,17 @@ email = forms.EmailField(widget=widgets.TextInput(attrs=REQUIRED_EMAIL_ATTRIBUTES)) password = forms.CharField(widget=widgets.PasswordInput(attrs=REQUIRED_ATTRIBUTES)) + def clean(self): + email = self.cleaned_data.get('email') + password = self.cleaned_data.get('password') + if email and password: + self.user_cache = authenticate(username=email, password=password) + if self.user_cache is None: + raise forms.ValidationError(_("Your combination of email and password was incorrect.")) + elif not self.user_cache.is_active: + raise forms.ValidationError(_("This user has been deactivated. Please contact us if this is in error.")) + return self.cleaned_data + class ParticipantAccountForm(forms.ModelForm): email = forms.EmailField(widget=widgets.TextInput(attrs=REQUIRED_EMAIL_ATTRIBUTES)) password = forms.CharField(widget=widgets.PasswordInput(attrs=REQUIRED_ATTRIBUTES)) diff -r 7784d52a6bd2 -r a5124f7b37f2 vcweb/core/urls.py --- a/vcweb/core/urls.py Thu Mar 31 12:57:25 2011 -0700 +++ b/vcweb/core/urls.py Thu Mar 31 13:40:56 2011 -0700 @@ -1,11 +1,11 @@ from django.conf.urls.defaults import patterns, url -from vcweb.core.views import Dashboard +from vcweb.core.views import Dashboard, LoginView ''' URLs defined by the core vcweb app. ''' urlpatterns = patterns('vcweb.core.views', url(r'^dashboard/?$', Dashboard.as_view(), name='dashboard'), - url(r'^accounts/login/$', 'login', name='login'), + url(r'^accounts/login/$', LoginView.as_view(), name='login'), url(r'^accounts/logout/$', 'logout', name='logout'), url(r'^accounts/register/$', 'register', name='register'), url(r'^accounts/profile/$', 'account_profile', name='profile'), diff -r 7784d52a6bd2 -r a5124f7b37f2 vcweb/core/views.py --- a/vcweb/core/views.py Thu Mar 31 12:57:25 2011 -0700 +++ b/vcweb/core/views.py Thu Mar 31 13:40:56 2011 -0700 @@ -1,11 +1,12 @@ from django.contrib import auth, messages from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User +from django.core.urlresolvers import reverse from django.http import HttpResponse from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext from django.utils.decorators import method_decorator -from django.views.generic import ListView, TemplateView, RedirectView +from django.views.generic import ListView, FormView, TemplateView from django.views.generic.base import TemplateResponseMixin from vcweb.core.forms import RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm from vcweb.core.models import Participant, Experiment, Institution, is_participant, is_experimenter @@ -26,26 +27,10 @@ return experiment raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, experiment_id)) -class ParticipantMixin(object): - @method_decorator(participant_required) +class AnonymousMixin(object): + @method_decorator(anonymous_required) def dispatch(self, *args, **kwargs): - return super(ParticipantMixin, self).dispatch(*args, **kwargs) - -""" -experimenter views -FIXME: add has_perms authorization to ensure that only experimenters can access -these. -""" -class ExperimenterMixin(object): - def _get_experiment(self, request, experiment_id): - experiment = Experiment.objects.get(pk=experiment_id) - if request.user.experimenter.pk == experiment.experimenter.pk: - return experiment - raise Experiment.DoesNotExist("Sorry, you do not appear to have access to %s" % experiment) - - @method_decorator(experimenter_required) - def dispatch(self, *args, **kwargs): - return super(ExperimenterMixin, self).dispatch(*args, **kwargs) + return super(AnonymousMixin, self).dispatch(*args, **kwargs) class Dashboard(ListView, TemplateResponseMixin): context_object_name = 'experiments' @@ -55,30 +40,35 @@ return ['experimenter-dashboard.html'] else: return ['participant-dashboard.html'] - def get_queryset(self): user = self.request.user if is_experimenter(user): return Experiment.objects.filter(experimenter__pk=self.request.user.experimenter.pk) else: - participant = user.participant experiment_dict = {} - for experiment in participant.experiments.all(): + for experiment in user.participant.experiments.exclude(status__in=(Experiment.INACTIVE, Experiment.PAUSED, Experiment.COMPLETED)): if not experiment.experiment_metadata in experiment_dict: experiment_dict[experiment.experiment_metadata] = dict([(choice[0], list()) for choice in Experiment.STATUS_CHOICES]) experiment_dict[experiment.experiment_metadata][experiment.status].append(experiment) logger.debug("experiment_dict %s" % experiment_dict) return experiment_dict -@login_required -def dashboard(request): - if is_participant(request.user): - return participant_index(request) - elif is_experimenter(request.user): - return ExperimenterDashboard.as_view() - else: - logger.warning("user %s isn't an experimenter or participant" % request.user) - return redirect('home') +class LoginView(FormView, AnonymousMixin): + form_class = LoginForm + template_name = 'registration/login.html' + + def form_valid(self, form): + request = self.request + user = form.user_cache + auth.login(request, user) + sha1 = hashlib.sha1() + sha1.update("%s%i%s" % (user.email, user.pk, datetime.now())) + request.session['authentication_token'] = base64.urlsafe_b64encode(sha1.digest()) + return super(LoginView, self).form_valid(form) + + def get_success_url(self): + return_url = self.request.GET.get('next') + return return_url if return_url else reverse('core:dashboard') @anonymous_required() def login(request): @@ -139,19 +129,10 @@ return render_to_response('registration/profile.html', { 'form': form }, context_instance=RequestContext(request)) ''' participant views ''' -""" participant home page """ -@participant_required -def participant_index(request): - participant = request.user.participant - experiment_dict = {} - for experiment in participant.experiments.all(): - if not experiment.experiment_metadata in experiment_dict: - experiment_dict[experiment.experiment_metadata] = dict([(choice[0], list()) for choice in Experiment.STATUS_CHOICES]) - experiment_dict[experiment.experiment_metadata][experiment.status].append(experiment) - - logger.debug("experiment_dict %s" % experiment_dict) - - return render_to_response('participant-index.html', locals(), context_instance=RequestContext(request)) +class ParticipantMixin(object): + @method_decorator(participant_required) + def dispatch(self, *args, **kwargs): + return super(ParticipantMixin, self).dispatch(*args, **kwargs) @login_required def instructions(request, experiment_id=None, namespace=None): @@ -167,6 +148,23 @@ return render_to_response(experiment.get_template_path('instructions.html'), locals(), context_instance=RequestContext(request)) +""" +experimenter views +FIXME: add has_perms authorization to ensure that only experimenters can access +these. +""" +class ExperimenterMixin(object): + def _get_experiment(self, request, experiment_id): + experiment = Experiment.objects.get(pk=experiment_id) + if request.user.experimenter.pk == experiment.experimenter.pk: + return experiment + raise Experiment.DoesNotExist("Sorry, you do not appear to have access to %s" % experiment) + + @method_decorator(experimenter_required) + def dispatch(self, *args, **kwargs): + return super(ExperimenterMixin, self).dispatch(*args, **kwargs) + + @experimenter_required def configure(request, experiment_id=None): # lookup game instance id (or create a new one?) |
From: <vir...@li...> - 2011-03-31 20:42:16
|
Subject: hg.virtualcommons 314 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/7784d52a6bd2 changeset: 314:7784d52a6bd2 user: Allen Lee <all...@as...> date: Thu Mar 31 12:57:25 2011 -0700 description: starting the switch to django class-based views diffstat: vcweb/core/templates/experimenter-dashboard.html | 72 ++++++++++++++++++++++++ vcweb/core/templates/experimenter-index.html | 67 ---------------------- vcweb/core/templates/monitor.html | 2 - vcweb/core/templates/participant-dashboard.html | 38 ++++++++++++ vcweb/core/templates/participant-index.html | 39 ------------- vcweb/core/urls.py | 8 +-- vcweb/core/views.py | 58 ++++++++++++++++--- vcweb/urls.py | 8 +- 8 files changed, 164 insertions(+), 128 deletions(-) diffs (390 lines): diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/templates/experimenter-dashboard.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/experimenter-dashboard.html Thu Mar 31 12:57:25 2011 -0700 @@ -0,0 +1,72 @@ +{% extends "base-experimenter.html" %} +{% block title %}Virtual Commons Web Experimenter Dashboard{% endblock %} +{% block head %} +{{ block.super }} +<script type='text/javascript'> + $(function() { + $('.confirm-experiment-action').each(function() { + var confirmable = $(this); + var description = confirmable.attr("title"); + confirmable.click(function() { + confirmable.fastConfirm({ + questionText: description + " - continue?", + onProceed: function(trigger) { + $(trigger).fastConfirm('close'); + window.location = $(trigger).attr("href"); + }, + onCancel: function(trigger) { + $(trigger).fastConfirm('close'); + } + }); + return false; + }); + }); + }); +</script> +{% endblock %} +{% block page %} +{{ block.super }} +{% comment%} +FIXME: replace these links eventually. +{% endcomment %} +<div id='navmenu'> + <a href='/admin'>add / configure an experiment</a> + <a href='/contact'>report a bug</a> +</div> +<div class='ui-state-highlight ui-corner-all'> + <span class='ui-icon ui-icon-info icon-left'></span> + Welcome to the experimenter dashboard. You are logged in as {{request.user.experimenter}}. +</div> +<h3>Your experiments</h3> +<div id="post"> + {% for e in experiments %} + <div class='notice ui-corner-all'> + {{e.status_line}} <span style='padding: 3px;' class='ui-state-highlight'><b>{{e.participants.count}} registered participants</b></span> + <ul class='horizontal'> + <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> + <li><a class='confirm-experiment-action' title='Creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> + {% if e.participants.count == 0 %} + <li> + <a title='Configure this experiment' href='{{e.controller_url}}/configure'><img src='/static/images/famfamfam/database_gear.png' alt='configure'/> configure</a> + </li> + <li> + <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> + <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> + </li> + {% else %} + <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> + {% endif %} + <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> + {% if e.is_active %} + <li><a title='stop this experiment' href='{{e.stop_url}}' class='confirm-experiment-action' style='background-image:none;' ><img src='/static/images/famfamfam/stop.png' alt=''/> stop</a></li> + {% endif %} + </ul> + </div> + {% empty %} + <div class='info infoIcon ui-corner-all'> + You are not currently running any experiments. + </div> + {% endfor %} +</div> +{% endblock page %} + diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/templates/experimenter-index.html --- a/vcweb/core/templates/experimenter-index.html Mon Mar 28 17:38:07 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -{% extends "base-experimenter.html" %} -{% block title %}Virtual Commons Web Experimenter Dashboard{% endblock %} -{% block head %} -{{ block.super }} -<script type='text/javascript'> - $(function() { - $('.confirm-experiment-action').each(function() { - var confirmable = $(this); - var description = confirmable.attr("title"); - confirmable.click(function() { - confirmable.fastConfirm({ - questionText: description + " - continue?", - onProceed: function(trigger) { - $(trigger).fastConfirm('close'); - window.location = $(trigger).attr("href"); - }, - onCancel: function(trigger) { - $(trigger).fastConfirm('close'); - } - }); - return false; - }); - }); - }); -</script> -{% endblock %} -{% block page %} -{{ block.super }} -{% comment%} -FIXME: replace these links eventually. -{% endcomment %} -<div id='navmenu'> - <a href='/admin'>add / configure an experiment</a> - <a href='/contact'>report a bug</a> -</div> -<div class='ui-state-highlight ui-corner-all'> - <span class='ui-icon ui-icon-info icon-left'></span> - Welcome to the experimenter dashboard. You are logged in as {{request.user.experimenter}}. -</div> -<h3>Your experiments</h3> -<div id="post"> - {% for e in experiments %} - <div class='notice ui-corner-all'> - {{e.status_line}} <span style='padding: 3px;' class='ui-state-highlight'><b>{{e.participants.count}} registered participants</b></span> - <ul class='horizontal'> - <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> - <li><a class='confirm-experiment-action' title='Creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> - <li> - <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> - <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> - </li> - <li> - <a title='Configure this experiment' href='{{e.controller_url}}/configure'><img src='/static/images/famfamfam/database_gear.png' alt='configure'/> configure</a> - </li> - <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> - <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> - <li><a title='stop this experiment' href='{{e.stop_url}}' class='confirm-experiment-action' style='background-image:none;' ><img src='/static/images/famfamfam/stop.png' alt=''/> stop</a></li> - </ul> - </div> - {% empty %} - <div class='info infoIcon ui-corner-all'> - You are not currently running any experiments. - </div> - {% endfor %} -</div> -{% endblock page %} - diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Mon Mar 28 17:38:07 2011 -0700 +++ b/vcweb/core/templates/monitor.html Thu Mar 31 12:57:25 2011 -0700 @@ -48,11 +48,9 @@ }); } } - function addExperimentMessage(message) { $("#experiment-messages").append($("<div style='font-size: 0.8em;line-height:0.9em;padding:3px;' class='ui-state-highlight' />").append(message)); } - $(function() { var experimentMessageDiv = document.getElementById('experiment-messages'); registerCallbacks({{ experiment.round_data.count }}, {{ experiment.current_round.sequence_number }}); diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/templates/participant-dashboard.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/participant-dashboard.html Thu Mar 31 12:57:25 2011 -0700 @@ -0,0 +1,38 @@ +{% extends "base-participant.html" %} + +{% block participant_socket_io %} +{% endblock %} +{% block head %} +{{block.super}} +<script type='text/javascript'> + $(function() { + $('[title]').qtip({position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'green', tip: 'bottomMiddle'} }); + }); +</script> +{% endblock %} + +{% block title %} +Virtual Commons Web Participant Dashboard +{% endblock %} + +{% block page %} +<div class='info infoIcon ui-corner-all'> + Welcome back, {{request.user.participant}}. Experiments you're participating in are listed below. +</div> + +<div id='experiments'> +{% for experiment_metadata, experiment_status_dict in experiments.items %} +<h3> {{ experiment_metadata.title }} </h3> +{% for experiment_status, experiments in experiment_status_dict.items %} +{% if experiments %} +<h4>{{experiments.0.get_status_display}}</h4> +{% for experiment in experiments %} +<div style='padding: 10px;' class='ui-state-highlight'> + <a title='This experiment is being run by {{experiment.experimenter}}' href='{{ experiment.participant_url }}'><span class='icon-left ui-icon {{experiment_status|lower}}'></span>{{ experiment.status_line }}, started {{experiment.current_round_start_time}}</a> +</div> +{% endfor %} +{% endif %} +{% endfor %} +{% endfor %} +</div> +{% endblock page %} diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/templates/participant-index.html --- a/vcweb/core/templates/participant-index.html Mon Mar 28 17:38:07 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -{% extends "base-participant.html" %} - -{% block participant_socket_io %} -{% endblock %} -{% block head %} -{{block.super}} -<script type='text/javascript'> - $(function() { - $('[title]').qtip({position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'green', tip: 'bottomMiddle'} }); - }); -</script> - -{% endblock %} - -{% block title %} -Virtual Commons Web Participant Dashboard -{% endblock %} - -{% block page %} -<div class='info infoIcon ui-corner-all'> - Welcome back, {{participant}}. Experiments you're participating in are listed below. -</div> - -<div id='experiments'> -{% for experiment_metadata, experiment_status_dict in experiment_dict.items %} -<h3> {{ experiment_metadata.title }} </h3> -{% for experiment_status, experiments in experiment_status_dict.items %} -{% if experiments %} -<h4>{{experiments.0.get_status_display}}</h4> -{% for experiment in experiments %} -<div style='padding: 10px;' class='ui-state-highlight'> - <a title='This experiment is being run by {{experiment.experimenter}}' href='{{ experiment.participant_url }}'><span class='icon-left ui-icon {{experiment_status|lower}}'></span>{{ experiment.status_line }}, started {{experiment.current_round_start_time}}</a> -</div> -{% endfor %} -{% endif %} -{% endfor %} -{% endfor %} -</div> -{% endblock page %} diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/urls.py --- a/vcweb/core/urls.py Mon Mar 28 17:38:07 2011 -0700 +++ b/vcweb/core/urls.py Thu Mar 31 12:57:25 2011 -0700 @@ -1,16 +1,14 @@ from django.conf.urls.defaults import patterns, url - +from vcweb.core.views import Dashboard ''' URLs defined by the core vcweb app. ''' urlpatterns = patterns('vcweb.core.views', - url(r'^dashboard/?$', 'dashboard', name='dashboard'), + url(r'^dashboard/?$', Dashboard.as_view(), name='dashboard'), url(r'^accounts/login/$', 'login', name='login'), url(r'^accounts/logout/$', 'logout', name='logout'), url(r'^accounts/register/$', 'register', name='register'), url(r'^accounts/profile/$', 'account_profile', name='profile'), - url(r'^experiment/$', 'experimenter_index', name='experimenter_index'), - url(r'^participate/$', 'participant_index', name='participant_index'), url(r'^participate/(?P<experiment_id>\d+)/instructions', 'instructions', name='instructions'), url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/(?P<experiment_id>\d+)/monitor$', 'monitor', name='monitor_experiment'), @@ -23,8 +21,6 @@ url(r'^experiment/(?P<experiment_id>\d+)/(?P<experiment_action>[\w-]+)$', 'experiment_controller', name='experiment_controller'), ) # add ajax actions - urlpatterns += patterns('vcweb.core.ajax', url(r'^ajax/(?P<experiment_id>\d+)/(<?P<experiment_action[\w-]+)$', 'experiment_controller'), ) - diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/core/views.py --- a/vcweb/core/views.py Mon Mar 28 17:38:07 2011 -0700 +++ b/vcweb/core/views.py Thu Mar 31 12:57:25 2011 -0700 @@ -4,6 +4,9 @@ from django.http import HttpResponse from django.shortcuts import render_to_response, redirect from django.template.context import RequestContext +from django.utils.decorators import method_decorator +from django.views.generic import ListView, TemplateView, RedirectView +from django.views.generic.base import TemplateResponseMixin from vcweb.core.forms import RegistrationForm, LoginForm, ParticipantAccountForm, ExperimenterAccountForm from vcweb.core.models import Participant, Experiment, Institution, is_participant, is_experimenter from vcweb.core.decorators import anonymous_required, experimenter_required, participant_required @@ -23,12 +26,56 @@ return experiment raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, experiment_id)) +class ParticipantMixin(object): + @method_decorator(participant_required) + def dispatch(self, *args, **kwargs): + return super(ParticipantMixin, self).dispatch(*args, **kwargs) + +""" +experimenter views +FIXME: add has_perms authorization to ensure that only experimenters can access +these. +""" +class ExperimenterMixin(object): + def _get_experiment(self, request, experiment_id): + experiment = Experiment.objects.get(pk=experiment_id) + if request.user.experimenter.pk == experiment.experimenter.pk: + return experiment + raise Experiment.DoesNotExist("Sorry, you do not appear to have access to %s" % experiment) + + @method_decorator(experimenter_required) + def dispatch(self, *args, **kwargs): + return super(ExperimenterMixin, self).dispatch(*args, **kwargs) + +class Dashboard(ListView, TemplateResponseMixin): + context_object_name = 'experiments' + def get_template_names(self): + user = self.request.user + if is_experimenter(user): + return ['experimenter-dashboard.html'] + else: + return ['participant-dashboard.html'] + + def get_queryset(self): + user = self.request.user + if is_experimenter(user): + return Experiment.objects.filter(experimenter__pk=self.request.user.experimenter.pk) + else: + participant = user.participant + experiment_dict = {} + for experiment in participant.experiments.all(): + if not experiment.experiment_metadata in experiment_dict: + experiment_dict[experiment.experiment_metadata] = dict([(choice[0], list()) for choice in Experiment.STATUS_CHOICES]) + experiment_dict[experiment.experiment_metadata][experiment.status].append(experiment) + logger.debug("experiment_dict %s" % experiment_dict) + return experiment_dict + @login_required def dashboard(request): if is_participant(request.user): return participant_index(request) elif is_experimenter(request.user): - return experimenter_index(request) + return ExperimenterDashboard.as_view() else: logger.warning("user %s isn't an experimenter or participant" % request.user) return redirect('home') @@ -119,15 +166,6 @@ return render_to_response(experiment.get_template_path('instructions.html'), locals(), context_instance=RequestContext(request)) -""" -experimenter views -FIXME: add has_perms authorization to ensure that only experimenters can access -these. -""" -@experimenter_required -def experimenter_index(request): - experiments = Experiment.objects.filter(experimenter=request.user.experimenter) - return render_to_response('experimenter-index.html', locals(), context_instance=RequestContext(request)) @experimenter_required def configure(request, experiment_id=None): diff -r 41a798482a48 -r 7784d52a6bd2 vcweb/urls.py --- a/vcweb/urls.py Mon Mar 28 17:38:07 2011 -0700 +++ b/vcweb/urls.py Thu Mar 31 12:57:25 2011 -0700 @@ -2,7 +2,7 @@ from django.contrib import admin from vcweb import settings -from django.views.generic.simple import direct_to_template +from django.views.generic.base import TemplateView from dajaxice.core import dajaxice_autodiscover # set up dajaxice URLs @@ -11,9 +11,9 @@ admin.autodiscover() urlpatterns = patterns('', - url(r'^$', direct_to_template, {'template':'index.html'}, name='home'), - url(r'^about/$', direct_to_template, {'template':'about.html'}, name='about'), - url(r'^contact/$', direct_to_template, {'template':'contact.html'}, name='contact'), + url(r'^$', TemplateView.as_view(template_name='index.html'), name='home'), + url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'), + url(r'^contact/$', TemplateView.as_view(template_name='contact.html'), name='contact'), url(r'^accounts/password/reset/$', 'django.contrib.auth.views.password_reset', name='password-reset'), url(r'^accounts/password_reset/$', 'django.contrib.auth.views.password_reset', {'template_name':'password_reset_form.html', 'email_template_name':'userpanel/password_reset_email.html'}), url(r'^accounts/password_reset/done/$', 'django.contrib.auth.views.password_reset_done', {'template_name':'password_reset_done.html'}), |
From: <vir...@li...> - 2011-03-29 00:37:20
|
Subject: hg.virtualcommons 313 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/41a798482a48 changeset: 313:41a798482a48 user: Allen Lee <all...@as...> date: Mon Mar 28 17:38:07 2011 -0700 description: going to add basic experiment configuration page for existing experiments (register # participants, text area for bulk email addresses for participants, etc.). advanced experiment configuration (round-by-round configuration) is still going to be punted on for the time being. diffstat: vcweb/core/templates/experimenter-index.html | 6 ++++-- vcweb/forestry/templates/forestry/participate.html | 3 ++- vcweb/forestry/templates/forestry/wait.html | 6 ++++-- vcweb/forestry/views.py | 10 ++++++---- vcweb/static/images/famfamfam/database_gear.png | vcweb/vcweb-tornadio.py | 3 --- 6 files changed, 16 insertions(+), 12 deletions(-) diffs (130 lines): diff -r b048a4b125b6 -r 41a798482a48 vcweb/core/templates/experimenter-index.html --- a/vcweb/core/templates/experimenter-index.html Sun Mar 27 22:07:13 2011 -0700 +++ b/vcweb/core/templates/experimenter-index.html Mon Mar 28 17:38:07 2011 -0700 @@ -44,11 +44,13 @@ {{e.status_line}} <span style='padding: 3px;' class='ui-state-highlight'><b>{{e.participants.count}} registered participants</b></span> <ul class='horizontal'> <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> - <li><a class='confirm-experiment-action' title='Clone this experiment. This creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> + <li><a class='confirm-experiment-action' title='Creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> <li> <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> - <a class='confirm-experiment-action' title='Register 25 participants for this experiment' href='{{e.controller_url}}/add-participants/25'><b>25 students</b></a> + </li> + <li> + <a title='Configure this experiment' href='{{e.controller_url}}/configure'><img src='/static/images/famfamfam/database_gear.png' alt='configure'/> configure</a> </li> <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> diff -r b048a4b125b6 -r 41a798482a48 vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 22:07:13 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Mon Mar 28 17:38:07 2011 -0700 @@ -46,7 +46,7 @@ {% block content %} <h3>Forestry round number {{ experiment.current_round.round_number }}</h3> {% for i in number_of_resource_divs %} -<div style="background: url('/static/images/forestry/pine-tree.png') repeat-x; width:{{max_width}}px; height: 79px;"> +<div style="background: url('/static/images/forestry/{{tree.name}}.png') repeat-x; width:{{max_width}}px; height: {{tree.height}}px;"> </div> {% endfor %} @@ -55,6 +55,7 @@ </div> {% endif %} + {% if resource_level.value == 0 %} <div style='padding: 8px; margin: auto; border: solid 1px; background: #E8E8E8 url(/static/images/forestry/deforestation.jpg) no-repeat center; height: 282px; width:425px;'> diff -r b048a4b125b6 -r 41a798482a48 vcweb/forestry/templates/forestry/wait.html --- a/vcweb/forestry/templates/forestry/wait.html Sun Mar 27 22:07:13 2011 -0700 +++ b/vcweb/forestry/templates/forestry/wait.html Mon Mar 28 17:38:07 2011 -0700 @@ -6,8 +6,10 @@ {% include "includes/tablesorter.html" %} <script type="text/javascript"> $(function() { - $('#participant-history').tablesorter({widgets: ['zebra'], sortList: [[0, 0]] }); - $('.tooltip').qtip({position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'green', tip: 'bottomMiddle'} }); + $('#participant-history').tablesorter({widgets: ['zebra'], + headers: { 0: {sorter: false}, 1: {sorter: false} } + }); + $('[title]').qtip({position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'green', tip: 'bottomMiddle'} }); var s = getCachedSocket(); s.on('message', function(json_string) { var json = jQuery.parseJSON(json_string); diff -r b048a4b125b6 -r 41a798482a48 vcweb/forestry/views.py --- a/vcweb/forestry/views.py Sun Mar 27 22:07:13 2011 -0700 +++ b/vcweb/forestry/views.py Mon Mar 28 17:38:07 2011 -0700 @@ -38,11 +38,9 @@ experiment_dict = {} for experiment in participant.experiments.filter(experiment_metadata=get_forestry_experiment_metadata()): status = experiment.get_status_display() - logger.debug("status is %s" % status) if not status in experiment_dict: experiment_dict[status] = list() experiment_dict[status].append(experiment) - return render_to_response('forestry/participant-index.html', locals(), context_instance=RequestContext(request)) @experimenter_required @@ -84,7 +82,6 @@ pass data.final_number_of_trees = resource_level.value participant_history.append(data) - logger.debug("participant history: %s" % participant_history) if experiment.is_round_in_progress: last_round_data = participant_history[-1] if experiment.current_round.pk == last_round_data.round_configuration.pk: @@ -140,7 +137,6 @@ messages.warning(request, error_message) return redirect('forestry:index') - import re quiz_question_re = re.compile(r'^quiz_question_(\d+)$') def quiz(request, experiment, participant): @@ -186,6 +182,11 @@ }, context_instance=RequestContext(request)) +trees = { + 'deciduous': { 'name': 'deciduous-tree', 'height': 32 }, + 'pine': {'name': 'pine-tree', 'height': 79 }, + } + def play(request, experiment, participant): form = HarvestDecisionForm(request.POST or None) @@ -210,6 +211,7 @@ max_width = number_of_trees_per_row * 30 number_of_resource_divs = range(0, resource_level.value / number_of_trees_per_row) resource_width = (resource_level.value % number_of_trees_per_row) * 30 + tree = trees['pine'] return render_to_response(experiment.current_round_template, locals(), context_instance=RequestContext(request)) diff -r b048a4b125b6 -r 41a798482a48 vcweb/static/images/famfamfam/database_gear.png Binary file vcweb/static/images/famfamfam/database_gear.png has changed diff -r b048a4b125b6 -r 41a798482a48 vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sun Mar 27 22:07:13 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Mon Mar 28 17:38:07 2011 -0700 @@ -20,10 +20,8 @@ from vcweb.core.models import ParticipantExperimentRelationship, ParticipantGroupRelationship, ChatMessage, Experimenter, Experiment - logger = logging.getLogger(__name__) - def info_json(message): return simplejson.dumps({'message_type': 'info', 'message': message}) @@ -222,7 +220,6 @@ def on_open(self, *args, **kwargs): # FIXME: verify user auth tokens extra = kwargs['extra'] - logger.debug('%s received extra: %s' % (self, extra)) #(auth_token, dot, participant_group_relationship_id) = extra.partition('.') #logger.debug("auth token: %s, id %s" % (auth_token, participant_group_relationship_id)) relationship_id = extra |
From: <vir...@li...> - 2011-03-28 05:06:41
|
Subject: hg.virtualcommons 312 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/b048a4b125b6 changeset: 312:b048a4b125b6 user: Allen Lee <all...@as...> date: Sun Mar 27 22:07:13 2011 -0700 description: adding deforestation image when the resource is exhausted. diffstat: vcweb/forestry/templates/forestry/participate.html | 7 ++++++- vcweb/static/images/forestry/deforestation.jpg | vcweb/static/images/forestry/pine-tree.gif | vcweb/static/images/forestry/plain-tree.gif | 4 files changed, 6 insertions(+), 1 deletions(-) diffs (30 lines): diff -r a4911736467c -r b048a4b125b6 vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 20:47:31 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 22:07:13 2011 -0700 @@ -55,6 +55,11 @@ </div> {% endif %} +{% if resource_level.value == 0 %} +<div style='padding: 8px; margin: auto; border: solid 1px; background: #E8E8E8 url(/static/images/forestry/deforestation.jpg) no-repeat center; height: 282px; width:425px;'> + +</div> +{% endif %} <div style='padding: 5px; margin: 8px 0px;' class='ui-state-highlight'> <span class='icon-left ui-icon ui-icon-info'> </span> There are <b>{{ resource_level.value }}</b> trees left. @@ -81,7 +86,7 @@ {% else %} <div class='alert ui-corner-all'> <span class='ui-icon ui-icon-alert icon-left'></span> - There aren't enough resources to harvest. + There are no longer enough trees to harvest. Please wait until the next round begins. </div> {% endif %} {% endblock content %} diff -r a4911736467c -r b048a4b125b6 vcweb/static/images/forestry/deforestation.jpg Binary file vcweb/static/images/forestry/deforestation.jpg has changed diff -r a4911736467c -r b048a4b125b6 vcweb/static/images/forestry/pine-tree.gif Binary file vcweb/static/images/forestry/pine-tree.gif has changed diff -r a4911736467c -r b048a4b125b6 vcweb/static/images/forestry/plain-tree.gif Binary file vcweb/static/images/forestry/plain-tree.gif has changed |
From: <vir...@li...> - 2011-03-28 05:06:40
|
Subject: hg.virtualcommons 311 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/a4911736467c changeset: 311:a4911736467c user: Allen Lee <all...@as...> date: Sun Mar 27 20:47:31 2011 -0700 description: changing goto url events to be consistent with regular message events. Should probably rename message to payload and make them generic events. diffstat: vcweb/core/templates/includes/experimenter.events.html | 7 +------ vcweb/forestry/templates/forestry/participate.html | 2 +- vcweb/forestry/views.py | 6 +++++- vcweb/vcweb-tornadio.py | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diffs (57 lines): diff -r 4c0fbb8805c0 -r a4911736467c vcweb/core/templates/includes/experimenter.events.html --- a/vcweb/core/templates/includes/experimenter.events.html Sun Mar 27 20:20:27 2011 -0700 +++ b/vcweb/core/templates/includes/experimenter.events.html Sun Mar 27 20:47:31 2011 -0700 @@ -7,12 +7,7 @@ if (! url) { url = "participate"; } - return { - 'type': 'goto', - 'experimenter_id': {{ request.user.experimenter.pk }}, - 'experiment_id': {{ experiment.pk }}, - 'url': url - }; + return createMessageEvent(url); } function createConnectionEvent() { return createMessageEvent("Initial connection", "connect"); diff -r 4c0fbb8805c0 -r a4911736467c vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 20:20:27 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 20:47:31 2011 -0700 @@ -80,7 +80,7 @@ </form> {% else %} <div class='alert ui-corner-all'> - <span class='ui-icon ui-icon-alert'></span> + <span class='ui-icon ui-icon-alert icon-left'></span> There aren't enough resources to harvest. </div> {% endif %} diff -r 4c0fbb8805c0 -r a4911736467c vcweb/forestry/views.py --- a/vcweb/forestry/views.py Sun Mar 27 20:20:27 2011 -0700 +++ b/vcweb/forestry/views.py Sun Mar 27 20:47:31 2011 -0700 @@ -75,7 +75,11 @@ data.group_regrowth = get_regrowth(group, round_data=round_data) resource_level = get_resource_level(group, round_data=round_data) try: - data.original_number_of_trees = resource_level.value + data.group_harvest.value - data.group_regrowth.value + # FIXME: make sure this is accurate + if resource_level.value == 100: + data.original_number_of_trees = 100 + else: + data.original_number_of_trees = resource_level.value + data.group_harvest.value - data.group_regrowth.value except AttributeError: pass data.final_number_of_trees = resource_level.value diff -r 4c0fbb8805c0 -r a4911736467c vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sun Mar 27 20:20:27 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sun Mar 27 20:47:31 2011 -0700 @@ -209,7 +209,7 @@ elif event.message_type == 'goto': experiment_id = event.experiment_id experiment = Experiment.objects.get(pk=experiment_id) - url = event.url + url = event.message notified_participants = connection_manager.send_goto(self, experiment, url) self.send(info_json("Sent goto:%s to all participants" % url)) logger.debug("sending all connected participants %s to %s" % (notified_participants, url)) |
From: <vir...@li...> - 2011-03-28 03:19:56
|
Subject: hg.virtualcommons 310 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/4c0fbb8805c0 changeset: 310:4c0fbb8805c0 user: Allen Lee <all...@as...> date: Sun Mar 27 20:20:27 2011 -0700 description: Replacing old confirm plugin w/ fastConfirm ParameterizedValue type_values are no longer required in the admin interface (blank=True) No longer showing activate if there's no registered participants in the monitor interface diffstat: vcweb/core/models.py | 6 +- vcweb/core/templates/experimenter-index.html | 6 +- vcweb/core/templates/monitor.html | 59 ++++++++++++++++++----------- 3 files changed, 42 insertions(+), 29 deletions(-) diffs (124 lines): diff -r 8ea1bc825ed9 -r 4c0fbb8805c0 vcweb/core/models.py --- a/vcweb/core/models.py Sun Mar 27 19:32:47 2011 -0700 +++ b/vcweb/core/models.py Sun Mar 27 20:20:27 2011 -0700 @@ -757,9 +757,9 @@ class ParameterizedValue(models.Model): parameter = models.ForeignKey(Parameter) string_value = models.CharField(max_length=512, null=True, blank=True) - int_value = models.IntegerField(null=True) - float_value = models.FloatField(null=True) - boolean_value = models.NullBooleanField(null=True) + int_value = models.IntegerField(null=True, blank=True) + float_value = models.FloatField(null=True, blank=True) + boolean_value = models.NullBooleanField(null=True, blank=True) date_created = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) diff -r 8ea1bc825ed9 -r 4c0fbb8805c0 vcweb/core/templates/experimenter-index.html --- a/vcweb/core/templates/experimenter-index.html Sun Mar 27 19:32:47 2011 -0700 +++ b/vcweb/core/templates/experimenter-index.html Sun Mar 27 20:20:27 2011 -0700 @@ -46,9 +46,9 @@ <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> <li><a class='confirm-experiment-action' title='Clone this experiment. This creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> <li> - <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> add 15 students</a> - <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'>20 students</a> - <a class='confirm-experiment-action' title='Register 25 participants for this experiment' href='{{e.controller_url}}/add-participants/25'>25 students</a> + <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> register <b>15 students</b></a> + <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'><b>20 students</b></a> + <a class='confirm-experiment-action' title='Register 25 participants for this experiment' href='{{e.controller_url}}/add-participants/25'><b>25 students</b></a> </li> <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> diff -r 8ea1bc825ed9 -r 4c0fbb8805c0 vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sun Mar 27 19:32:47 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sun Mar 27 20:20:27 2011 -0700 @@ -16,24 +16,28 @@ } } function registerCallbacks(round_data_count, active_round_number) { - $('.confirm-experiment-action').click(function() { - Dajaxice.vcweb.core.experiment_controller(update, {'experiment_id': {{experiment_id}}, 'action':this.name}); - $('#statusDiv').hide('fast'); - $('#experimentData').hide('fast'); - $('#statusSpinner').show('fast'); - return false; + $('.confirm-experiment-action').each(function() { + var confirmable = $(this); + var description = confirmable.attr("title"); + var action= $(this).attr("name"); + confirmable.click(function() { + confirmable.fastConfirm({ + questionText: description + " - continue?", + onProceed: function(trigger) { + Dajaxice.vcweb.core.experiment_controller(update, {'experiment_id': {{experiment_id}}, 'action':action}); + $('#statusDiv').hide('fast'); + $('#experimentData').hide('fast'); + $('#statusSpinner').show('fast'); + $(trigger).fastConfirm('close'); + }, + onCancel: function(trigger) { + $(trigger).fastConfirm('close'); + } + }); + return false; + }); }); - $('.confirm-experiment-action').confirm({ - timeout: 5000, - dialogShow: 'fadeIn', - dialogSpeed: 'fast', - buttons: { - wrapper: "<button></button>", - separator: ' ' - }, - msg: ' You are about to modify the experiment. Continue?' - }); - $('#statusSpinner').hide('fast'); + $('#statusSpinner').hide(); $('#statusDiv').show('fast'); $('#experimentData').show('fast'); $('#statusDiv [title]').qtip(qtipOptions); @@ -137,6 +141,7 @@ </div> <div id='statusDiv'> {% block status %} + {% with participant_count=experiment.participants.count %} <fieldset class='small ui-corner-all'> <legend>round status</legend> <ul id='actions' class='actions'> @@ -151,20 +156,28 @@ <li><a class='confirm-experiment-action' name='advance_to_next_round' href='advance-to-next-round' title='Stops the current round if necessary and advances to the next round.'> <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/control_fastforward_blue.png);' ></span>advance to next round</a></li> {% else %} - <li><a class='confirm-experiment-action' name='setup_test_participants' - href='setup-test-participants/20' title='Set up 20 participants'>Activate experiment with 20 participants</a></li> - <li><a class='confirm-experiment-action' name='activate' href='activate' title='You must first activate an experiment before you can run it.'> - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' ></span>activate</a></li> + {% if participant_count == 0 %} + <div class='alert alertIcon ui-corner-all'> + There are no registered participants. Please <a href='{% url core:dashboard %}'>return to the dashboard to register participants.</a> + </div> + {% else %} + <li><a title='You must first activate an experiment before you can run it.' class='confirm-experiment-action' name='activate' + href='activate'><span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' ></span>activate</a> + </li> + {%endif%} {% endif %} </ul> <br/> - <ul class='messages tooltip' title='Round instructions: {{experiment.actions_help_text}}'> - <li>{{ experiment.round_status_display }}</li> + <ul class='messages'> + <li title='{{experiment.actions_help_text}}'>{{ experiment.round_status_display }}</li> <li>Type: {{ experiment.current_round.get_round_type_display }}</li> <li>Round started on {{ experiment.current_round_start_time }}</li> <li>Time remaining: {{ experiment.time_remaining }}</li> + <li>Registered participants: <b>{{participant_count}}</b> + </li> </ul> </fieldset> + {% endwith %} {% endblock status %} </div> </div> |
From: <vir...@li...> - 2011-03-28 02:32:16
|
Subject: hg.virtualcommons 309 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/8ea1bc825ed9 changeset: 309:8ea1bc825ed9 user: Allen Lee <all...@as...> date: Sun Mar 27 19:32:47 2011 -0700 description: switching confirmations to jquery.fastconfirm plugin, seems much nicer. adding clone / test participant management to experiments. diffstat: vcweb/core/models.py | 56 ++++--- vcweb/core/templates/base-experimenter.html | 19 +- vcweb/core/templates/experimenter-index.html | 44 ++++- vcweb/core/templates/includes/jquery.confirm.html | 2 + vcweb/core/templates/monitor.html | 2 - vcweb/core/urls.py | 5 +- vcweb/core/views.py | 46 +++++ vcweb/static/css/jquery.fastconfirm.css | 220 +++++++++++++++++++++++++++ vcweb/static/css/style.css | 59 +++++++- vcweb/static/images/famfamfam/page_copy.png | vcweb/static/js/jquery.fastconfirm.min.js | 1 + 11 files changed, 406 insertions(+), 48 deletions(-) diffs (606 lines): diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/models.py --- a/vcweb/core/models.py Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/core/models.py Sun Mar 27 19:32:47 2011 -0700 @@ -241,22 +241,6 @@ return "%s.%s" % (self.namespace, self.pk) @property - def participant_url(self): - return "/%s/participate" % self.get_absolute_url() - - @property - def management_url(self): - return "/%s/experimenter" % self.get_absolute_url() - - @property - def stop_url(self): - return "%s/stop" % self.controller_url - - @property - def monitor_url(self): - return "%s/monitor" % self.controller_url - - @property def round_status_display(self): return "Round %s of %s, %s" % (self.current_round.sequence_number, self.experiment_configuration.final_sequence_number, self.get_status_display()) @@ -273,9 +257,29 @@ return self.experiment_metadata.namespace @property + def management_url(self): + return "/%s/experimenter" % self.get_absolute_url() + + @property + def stop_url(self): + return "%s/stop" % self.controller_url + + @property + def monitor_url(self): + return "%s/monitor" % self.controller_url + + @property + def clone_url(self): + return "%s/clone" % self.controller_url + + @property def controller_url(self): return "/experiment/%s" % self.pk + @property + def participant_url(self): + return "/%s/participate" % self.get_absolute_url() + def get_absolute_url(self): return "%s/%s" % (self.experiment_metadata.namespace, self.pk) @@ -351,19 +355,22 @@ return pdvs.filter(submitted=False).count() == 0 ''' hardcoded defaults for the slovakia pretest ''' - def setup_test_participants(self, number_of_students=20, institution_name='Slovak Academy of Sciences', institution_url='http://www.sav.sk', email_suffix='sav.sk', test_password='test'): + def setup_test_participants(self, count=20, institution_name='Slovak Academy of Sciences', institution_url='http://www.sav.sk', email_suffix='sav.sk', test_password='test'): if self.participants.count() > 0: logger.debug("This experiment %s already has %d participants - aborting" % (self, self.participants.count())) return (institution, created) = Institution.objects.get_or_create(name=institution_name, url=institution_url) - for i in xrange(1, number_of_students+1): - email = 's%d@%s' % (i, email_suffix) - u = User.objects.create_user(email, email, test_password) - u.first_name = 'Student' - u.last_name = u"%d" % i - u.save() - p = Participant.objects.create(user=u, institution=institution) + for i in xrange(1, count+1): + email = u's%d@%s' % (i, email_suffix) + try: + u = User.objects.get(username=email) + except User.DoesNotExist: + u = User.objects.create_user(username=email, email=email, password=test_password) + u.first_name = u'Student' + u.last_name = u"%d" % i + u.save() + (p, created) = Participant.objects.get_or_create(user=u, institution=institution) ParticipantExperimentRelationship.objects.create(participant=p, experiment=self, created_by=u) def log(self, log_message): @@ -459,6 +466,7 @@ return signals.round_ended.send(sender, experiment=self, round_configuration=self.current_round) def stop(self): + self.log("Stopping experiment and flagging as inactive.") self.status = 'INACTIVE' self.save() diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/templates/base-experimenter.html --- a/vcweb/core/templates/base-experimenter.html Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/core/templates/base-experimenter.html Sun Mar 27 19:32:47 2011 -0700 @@ -1,14 +1,13 @@ {% extends "base.html" %} - {% block head %} {{ block.super}} -<script type='text/javascript' src='/static/js/jquery.confirm.min.js'></script> +<script type='text/javascript'> + var qtipOptions = {position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'dark', tip: 'bottomMiddle'} }; + $(function() { + $('[title]').qtip(qtipOptions); + }); +</script> +{% include "includes/jquery.confirm.html" %} {% endblock %} - -{% block title %} - Virtual Commons Web Experimenter Interface -{% endblock %} - -{% block header %} - {% include "includes/experimenter-nav-menu.html" %} -{% endblock %} +{% block title %}Virtual Commons Web Experimenter Interface{% endblock %} +{% block header %}{% include "includes/experimenter-nav-menu.html" %}{% endblock %} diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/templates/experimenter-index.html --- a/vcweb/core/templates/experimenter-index.html Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/core/templates/experimenter-index.html Sun Mar 27 19:32:47 2011 -0700 @@ -1,7 +1,29 @@ {% extends "base-experimenter.html" %} - {% block title %}Virtual Commons Web Experimenter Dashboard{% endblock %} - +{% block head %} +{{ block.super }} +<script type='text/javascript'> + $(function() { + $('.confirm-experiment-action').each(function() { + var confirmable = $(this); + var description = confirmable.attr("title"); + confirmable.click(function() { + confirmable.fastConfirm({ + questionText: description + " - continue?", + onProceed: function(trigger) { + $(trigger).fastConfirm('close'); + window.location = $(trigger).attr("href"); + }, + onCancel: function(trigger) { + $(trigger).fastConfirm('close'); + } + }); + return false; + }); + }); + }); +</script> +{% endblock %} {% block page %} {{ block.super }} {% comment%} @@ -9,8 +31,7 @@ {% endcomment %} <div id='navmenu'> <a href='/admin'>add / configure an experiment</a> - <a href='/experimenter/data'>download data</a> - <a href='http://commons.asu.edu/contact'>report a bug</a> + <a href='/contact'>report a bug</a> </div> <div class='ui-state-highlight ui-corner-all'> <span class='ui-icon ui-icon-info icon-left'></span> @@ -20,11 +41,18 @@ <div id="post"> {% for e in experiments %} <div class='notice ui-corner-all'> - {{e.status_line}} - <ul class='horizontal' id='horizontal'> - <li><a href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> + {{e.status_line}} <span style='padding: 3px;' class='ui-state-highlight'><b>{{e.participants.count}} registered participants</b></span> + <ul class='horizontal'> + <li><a title='Monitor and control this experiment' href='{{e.monitor_url}}'><img src='/static/images/famfamfam/zoom.png' alt='General experiment monitoring interface'/> monitor</a></li> + <li><a class='confirm-experiment-action' title='Clone this experiment. This creates a new copy of this experiment with the exact same configuration but no registered participants.' href='{{e.clone_url}}'><img src='/static/images/famfamfam/page_copy.png' alt='Clone experiment'/> clone</a></li> + <li> + <a class='confirm-experiment-action' title='Register 15 participants for this experiment' href='{{e.controller_url}}/add-participants/15'><img src='/static/images/famfamfam/add.png' alt='add participants'/> add 15 students</a> + <a class='confirm-experiment-action' title='Register 20 participants for this experiment' href='{{e.controller_url}}/add-participants/20'>20 students</a> + <a class='confirm-experiment-action' title='Register 25 participants for this experiment' href='{{e.controller_url}}/add-participants/25'>25 students</a> + </li> <!-- <li><a href='{{e.management_url}}'><img src='/static/images/famfamfam/application_go.png' alt='Custom management interface'/> manage (unfinished)</a></li> --> - <li><a href='{{e.stop_url}}' class='confirm-experiment-action' style='background-image:none;' ><img src='/static/images/famfamfam/stop.png' alt=''/> stop</a></li> + <li><a title='clear all participants' href='{{e.controller_url}}/clear-participants' class='confirm-experiment-action'><img src='/static/images/famfamfam/delete.png' alt=''/> clear all participants</a></li> + <li><a title='stop this experiment' href='{{e.stop_url}}' class='confirm-experiment-action' style='background-image:none;' ><img src='/static/images/famfamfam/stop.png' alt=''/> stop</a></li> </ul> </div> {% empty %} diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/templates/includes/jquery.confirm.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/includes/jquery.confirm.html Sun Mar 27 19:32:47 2011 -0700 @@ -0,0 +1,2 @@ +<link href="/static/css/jquery.fastconfirm.css" rel="stylesheet" type="text/css" media="screen" /> +<script type="text/javascript" src="/static/js/jquery.fastconfirm.min.js"></script> diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sun Mar 27 19:32:47 2011 -0700 @@ -4,7 +4,6 @@ {% include "includes/experimenter.events.html" %} {% include "includes/socket.io.html" %} <script type='text/javascript'> - var qtipOptions = {position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'dark', tip: 'bottomMiddle'} }; function update(json) { if (json == Dajaxice.EXCEPTION) { console.error("dajaxice error: " + json); @@ -74,7 +73,6 @@ } scrollToBottom(experimentMessageDiv); }); - $('[title]').qtip(qtipOptions); $('#refreshAllParticipants').click(function(evt) { console.log("sending refresh event"); s.send(createRefreshEvent()); diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/urls.py --- a/vcweb/core/urls.py Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/core/urls.py Sun Mar 27 19:32:47 2011 -0700 @@ -15,8 +15,11 @@ url(r'^participate/(?P<namespace>\w+)/instructions', 'instructions', name='namespace_instructions'), url(r'^experiment/(?P<experiment_id>\d+)/monitor$', 'monitor', name='monitor_experiment'), url(r'^experiment/(?P<experiment_id>\d+)/configure$', 'configure', name='configure_experiment'), + url(r'^experiment/(?P<experiment_id>\d+)/clone$', 'clone', name='clone'), + url(r'^experiment/(?P<experiment_id>\d+)/add-participants/(?P<count>[\d]+)$', 'add_participants', name='add_participants'), + url(r'^experiment/(?P<experiment_id>\d+)/clear-participants', 'clear_participants', name='clear_participants'), url(r'^experiment/(?P<experiment_id>\d+)/download/(?P<file_type>[\w]+)$', 'download_data', name='download_data'), -# experiment controller actions +# experiment controller actions are the most general, needs to be matched at the very end url(r'^experiment/(?P<experiment_id>\d+)/(?P<experiment_action>[\w-]+)$', 'experiment_controller', name='experiment_controller'), ) # add ajax actions diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/core/views.py --- a/vcweb/core/views.py Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/core/views.py Sun Mar 27 19:32:47 2011 -0700 @@ -17,6 +17,12 @@ """ account registration / login / logout / profile views """ +def _get_experiment(request, experiment_id): + experiment = Experiment.objects.get(pk=experiment_id) + if request.user.experimenter == experiment.experimenter: + return experiment + raise Experiment.DoesNotExist("Sorry, %s - you do not have access to experiment %s" % (experiment.experimenter, experiment_id)) + @login_required def dashboard(request): if is_participant(request.user): @@ -140,6 +146,46 @@ experiment_id) @experimenter_required +def clone(request, experiment_id=None, count=0): + try: + experiment = _get_experiment(request, experiment_id) + cloned_experiment = experiment.clone() + if count > 0: + cloned_experiment.setup_test_participants(count=count) + logger.debug("cloned experiment: %s" % cloned_experiment) + except Experiment.DoesNotExist: + error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id + logger.warning(error_message) + messages.warning(request, error_message) + return redirect('core:dashboard') + +@experimenter_required +def add_participants(request, experiment_id=None, count=0): + try: + experiment = _get_experiment(request, experiment_id) + count = int(count) + if count > 0: + experiment.setup_test_participants(count=count) + except Experiment.DoesNotExist: + error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id + logger.warning(error_message) + messages.warning(request, error_message) + return redirect('core:dashboard') + +@experimenter_required +def clear_participants(request, experiment_id=None): + try: + experiment = _get_experiment(request, experiment_id) + if experiment.participants.count() > 0: + experiment.participants.all().delete() + except Experiment.DoesNotExist: + error_message = "Tried to monitor non-existent experiment (id %s)" % experiment_id + logger.warning(error_message) + messages.warning(request, error_message) + return redirect('core:dashboard') + + +@experimenter_required def monitor(request, experiment_id=None): try: experiment = Experiment.objects.get(pk=experiment_id) diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/static/css/jquery.fastconfirm.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/static/css/jquery.fastconfirm.css Sun Mar 27 19:32:47 2011 -0700 @@ -0,0 +1,220 @@ +@charset "utf-8"; + +/*********************/ +/* Can't touch this! */ +/*********************/ + +.fast_confirm { + position: absolute; + + /* Position off-screen, show only when everything is ready */ + top: -500px; + left: -500px; +} +/* IE6 */ +.fast_confirm { + _border-left-color: pink; + _border-bottom-color: pink; + _border-right-color: pink; + _filter: chroma(color=pink); +} + + +/*******************************/ +/* You can configure from here */ +/*******************************/ + +/* BOX */ + +.fast_confirm { + background-color: #fff; + font-size: 14px; + text-align: center; + padding: 6px; + + border: 1px solid #aaa; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + + -moz-box-shadow: 0 0 4px #000; + -webkit-box-shadow: 0 0 4px #000; + box-shadow: 0 0 4px #000; +} + + +/* ARROWS */ + +/* Top arrow */ +.fast_confirm .fast_confirm_top.fast_confirm_arrow { + position: absolute; + top: -10px; + + border-color: transparent transparent #fff; + border-style: solid; + border-width: 0 10px 10px; + height: 0; + width: 0; +} +.fast_confirm .fast_confirm_top.fast_confirm_arrow_border { + position: absolute; + top: -12px; + + border-color: transparent transparent #aaa; + border-style: solid; + border-width: 0 12px 12px; + height: 0; + width: 0; +} + +/* Right arrow */ +.fast_confirm .fast_confirm_right.fast_confirm_arrow { + position: absolute; + right: -10px; + + border-color: transparent transparent transparent #fff; + border-style: solid; + border-width: 10px 0 10px 10px; + height: 0; + width: 0; +} +.fast_confirm .fast_confirm_right.fast_confirm_arrow_border { + position: absolute; + right: -12px; + + border-color: transparent transparent transparent #aaa; + border-style: solid; + border-width: 12px 0 12px 12px; + height: 0; + width: 0; +} + +/* Bottom arrow */ +.fast_confirm .fast_confirm_bottom.fast_confirm_arrow { + position: absolute; + bottom: -10px; + + border-color: #fff transparent transparent; + border-style: solid; + border-width: 10px 10px 0 10px; + height: 0; + width: 0; +} +.fast_confirm .fast_confirm_bottom.fast_confirm_arrow_border { + position: absolute; + bottom: -12px; + + border-color: #aaa transparent transparent; + border-style: solid; + border-width: 12px 12px 0 12px; + height: 0; + width: 0; +} + +/* Left arrow */ +.fast_confirm .fast_confirm_left.fast_confirm_arrow { + position: absolute; + left: -10px; + + border-color: transparent #fff transparent transparent; + border-style: solid; + border-width: 10px 10px 10px 0; + height: 0; + width: 0; +} +.fast_confirm .fast_confirm_left.fast_confirm_arrow_border { + position: absolute; + left: -12px; + + border-color: transparent #aaa transparent transparent; + border-style: solid; + border-width: 12px 12px 12px 0; + height: 0; + width: 0; +} + + +/* BUTTONS */ + +.fast_confirm button { + margin: 10px; + padding: 5px 10px; + + font-weight: bold; + + color: #fff; + + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +/* Proceed button */ +.fast_confirm button.fast_confirm_proceed { + border: 1px solid #128123; + + color: #fff; + + text-shadow: 0 -1px 0 hsla(120,100%,0%,.5); + + background: #00aa00; + background: -webkit-gradient( linear, left top, left bottom, color-stop(.2, #00aa00), color-stop(1, #006600) ); + background: -moz-linear-gradient( center top, #00aa00 20%, #006600 100% ); + + -webkit-box-shadow: + inset 0 1px 1px hsla(0,100%,100%,.4), + inset 0 -1px 0 hsla(0,100%,100%,.3), + 0 2px 0 hsla(120,77%,26%,1), + 0 4px 2px hsla(122,100%,0%,.5); + + -moz-box-shadow: + inset 0 1px 1px hsla(0,100%,100%,.4), + inset 0 -1px 0 hsla(0,100%,100%,.3), + 0 2px 0 hsla(120,77%,26%,1), + 0 4px 2px hsla(122,100%,0%,.5); + + box-shadow: + inset 0 1px 1px hsla(0,100%,100%,.4), + inset 0 -1px 0 hsla(0,100%,100%,.3), + 0 2px 0 hsla(122,77%,26%,1), + 0 4px 2px hsla(122,100%,0%,.5); +} +.fast_confirm button.fast_confirm_proceed:hover { + background: -webkit-gradient( linear, left top, left bottom, color-stop(.2, #00dd00), color-stop(1, #00aa00) ); + background: -moz-linear-gradient( center top, #00dd00 20%, #00aa00 100% ); +} + +/* Cancel button */ +.fast_confirm button.fast_confirm_cancel { + border: 1px solid #128123; + + color: #fff; + + text-shadow: 0 -1px 0 hsla(0,100%,0%,.5); + + background: #ff2222; + background: -webkit-gradient( linear, left top, left bottom, color-stop(.2, #ff2222), color-stop(1, #aa0000) ); + background: -moz-linear-gradient( center top, #ff2222 20%, #aa0000 100% ); + + -webkit-box-shadow: + inset 0 1px 1px hsla(0,100%,100%,.4), + inset 0 -1px 0 hsla(0,100%,100%,.3), + 0 2px 0 hsla(0,77%,26%,1), + 0 4px 2px hsla(2,100%,0%,.5); + + -moz-box-shadow: + inset 0 1px 1px hsla(0,100%,100%,.4), + inset 0 -1px 0 hsla(0,100%,100%,.3), + 0 2px 0 hsla(0,77%,26%,1), + 0 4px 2px hsla(2,100%,0%,.5); + + box-shadow: + inset 0 1px 1px hsla(0,100%,100%,.4), + inset 0 -1px 0 hsla(0,100%,100%,.3), + 0 2px 0 hsla(0,77%,26%,1), + 0 4px 2px hsla(2,100%,0%,.5); +} +.fast_confirm button.fast_confirm_cancel:hover { + background: -webkit-gradient( linear, left top, left bottom, color-stop(.2, #ff6666), color-stop(1, #ff2222) ); + background: -moz-linear-gradient( center top, #ff6666 20%, #ff2222 100% ); +} diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/static/css/style.css --- a/vcweb/static/css/style.css Sun Mar 27 14:51:53 2011 -0700 +++ b/vcweb/static/css/style.css Sun Mar 27 19:32:47 2011 -0700 @@ -181,16 +181,16 @@ text-decoration: none; font-size: 0.9em; } -#horizontal a { +ul.horizontal>li>a { background: url("/static/images/separator.gif") bottom right no-repeat; padding-left: 8px; padding-right: 8px; text-decoration: none; } -#horizontal a:hover { +ul.horizontal>li>a:hover { text-decoration: underline; } -#horizontal li { +ul.horizontal>li { float: left; margin: 6px 0px 0px 0px; padding: 0; @@ -250,3 +250,56 @@ #chatText { width: 100%; } +#jqDialog_box { + background: #f5f5f5; + position: absolute; + width: 450px; + height: 150px; + font-family: Arial; + border-width: 1px 3px 3px 1px; + border-style: solid; + border-color: #ccc; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + -khtml-border-radius: 6px; + border-radius: 6px; + -moz-box-shadow: 0 0 30px #e6e6e6; +} +#jqDialog_content { + margin: 10px; + font-weight: bold; + font-size: 12px; + height: 90px; + overflow: hidden; +} +#jqDialog_options { + margin: 10px; + text-align: center; +} +#jqDialog_options button { + font-family: Arial; + margin-right: 5px; + background: #000; + border: 0px; + font-size: 1.5em; + color: #fff; + width: auto; + cursor: pointer; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -khtml-border-radius: 3px; + border-radius: 3px; +} +#jqDialog_input { + padding: 4px; + width: 250px; +} +#jqDialog_close { + background: none; + border: none; + float: right; + font-weight: bold; + font-size: 10px; + color: #ff0000; + cursor: pointer; +} diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/static/images/famfamfam/page_copy.png Binary file vcweb/static/images/famfamfam/page_copy.png has changed diff -r 2005e4646d8d -r 8ea1bc825ed9 vcweb/static/js/jquery.fastconfirm.min.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/static/js/jquery.fastconfirm.min.js Sun Mar 27 19:32:47 2011 -0700 @@ -0,0 +1,1 @@ +(function(b){var a={init:function(c){var d;if(!this.length){return this}b.fastConfirm={defaults:{position:"bottom",offset:{top:0,left:0},zIndex:10000,eventToBind:false,questionText:"Are you sure?",proceedText:"Yes",cancelText:"No",targetElement:null,unique:false,fastConfirmClass:"fast_confirm",onProceed:function(e){e.fastConfirm("close");return true},onCancel:function(e){e.fastConfirm("close");return false}}};d=b.extend(b.fastConfirm.defaults,c||{});return this.each(function(){var h=this,p=b(this),r=b('<button class="'+d.fastConfirmClass+'_proceed">'+d.proceedText+"</button>"),m=b('<button class="'+d.fastConfirmClass+'_cancel">'+d.cancelText+"</button>"),j=b('<div class="'+d.fastConfirmClass+'"><div class="'+d.fastConfirmClass+'_arrow_border"></div><div class="'+d.fastConfirmClass+'_arrow"></div>'+d.questionText+"<br/></div>"),q=b("div."+d.fastConfirmClass+"_arrow",j),n=b("div."+d.fastConfirmClass+"_arrow_border",j),g,o,f=d.targetElement?b(d.targetElement,p):p,k=f.offset(),l,e,i=function(){if(!p.data("fast_confirm.box")){p.data("fast_confirm.params.fastConfirmClass",d.fastConfirmClass);if(d.unique){b("."+d.fastConfirmClass+"_trigger").fastConfirm("close")}r.bind("click.fast_confirm",function(){p.data("fast_confirm.box",j).addClass(d.fastConfirmClass+"_trigger");d.onProceed(p);if(d.eventToBind){h[d.eventToBind]()}});m.bind("click.fast_confirm",function(){p.data("fast_confirm.box",j).addClass(d.fastConfirmClass+"_trigger");d.onCancel(p)});j.attr("tabIndex",-1).bind("keydown.fast_confirm",function(s){if(s.keyCode&&s.keyCode===27){p.fastConfirm("close")}});j.append(r).append(m);b("body").append(j);switch(d.position){case"top":g=d.fastConfirmClass+"_bottom";o=d.fastConfirmClass+"_bottom";q.addClass(g).css("left",j.outerWidth()/2-q.outerWidth()/2);n.addClass(o).css("left",j.outerWidth()/2-n.outerWidth()/2);l=k.top-j.outerHeight()-n.outerHeight()+d.offset.top;e=k.left-j.outerWidth()/2+f.outerWidth()/2+d.offset.left;break;case"right":g=d.fastConfirmClass+"_left";o=d.fastConfirmClass+"_left";q.addClass(g).css("top",j.out |
From: <vir...@li...> - 2011-03-27 21:51:26
|
Subject: hg.virtualcommons 308 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/2005e4646d8d changeset: 308:2005e4646d8d user: Allen Lee <all...@as...> date: Sun Mar 27 14:51:53 2011 -0700 description: fixing html validation errors diffstat: vcweb/core/templates/experimenter-index.html | 2 -- vcweb/core/templates/monitor.html | 25 ++++++++++++++++--------- vcweb/core/templates/registration/login.html | 2 +- vcweb/forestry/templates/forestry/participate.html | 6 +++--- vcweb/forestry/templates/forestry/wait.html | 2 +- vcweb/static/css/style.css | 3 +++ 6 files changed, 24 insertions(+), 16 deletions(-) diffs (131 lines): diff -r f107436c2323 -r 2005e4646d8d vcweb/core/templates/experimenter-index.html --- a/vcweb/core/templates/experimenter-index.html Sun Mar 27 01:43:13 2011 -0700 +++ b/vcweb/core/templates/experimenter-index.html Sun Mar 27 14:51:53 2011 -0700 @@ -2,8 +2,6 @@ {% block title %}Virtual Commons Web Experimenter Dashboard{% endblock %} -{% block header %} {% include "includes/experimenter-nav-menu.html" %} {% endblock header %} - {% block page %} {{ block.super }} {% comment%} diff -r f107436c2323 -r 2005e4646d8d vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sun Mar 27 01:43:13 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sun Mar 27 14:51:53 2011 -0700 @@ -87,7 +87,6 @@ }); scrollToBottom(experimentMessageDiv); }); - </script> </script> {% endblock %} {% block title %} @@ -114,12 +113,20 @@ <legend>Experiment management</legend> <ul class='actions'> <li><span id='refreshAllParticipants' title='Sends a page refresh to all connected participants.' class='clickable' > - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_refresh.png);' alt=''></span>refresh all participants</a></li> + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_refresh.png);'></span> + refresh all participants</span> + </li> <li><span id='gotoUrl' title='Moves all connected participants from waiting page to active page.' class='clickable' > - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_right.png);' alt=''></span>transition all participants to next round</a></li> + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/arrow_right.png);'></span> + transition all participants to next round</span> + </li> <li> - <a href='download/csv'><span class='vcweb-icon ui-icon icon-left' style='margin: 8px 0.15em 0px 0px; background:url(/static/images/download-icon.png);' alt=''></span>download data as <img src='/static/images/famfamfam/page_white_text.png' style='margin: 5px 0 0 0;' alt=''> csv</a> | - <a href='download/xls'><img src='/static/images/famfamfam/page_white_excel.png' style='margin: 5px 0 0 0;' alt=''/> xls</a></li> + <a href='download/csv'> + <span class='vcweb-icon ui-icon icon-left' style='margin: 8px 0.15em 0px 0px; background:url(/static/images/download-icon.png);'></span> + download data as <img src='/static/images/famfamfam/page_white_text.png' style='margin: 5px 0 0 0;' alt='' /> csv + </a> | + <a href='download/xls'><img src='/static/images/famfamfam/page_white_excel.png' style='margin: 5px 0 0 0;' alt=''/> xls</a> + </li> </ul> </fieldset> <div class='experiment-dashboard'> @@ -138,18 +145,18 @@ {% if experiment.is_active %} {% if experiment.is_round_in_progress %} <li><a class='confirm-experiment-action' name='end_round' href='end-round' title='Stops the current round.'> - <span class='vcweb-icon icon-left ui-icon' style='background: url(/static/images/famfamfam/control_stop_blue.png);' alt=''></span>end round</a></li> + <span class='vcweb-icon icon-left ui-icon' style='background: url(/static/images/famfamfam/control_stop_blue.png);' ></span>end round</a></li> {% else %} <li><a class='confirm-experiment-action' name='start_round' href='start-round' title='Starts the round.'> - <span class='ui-icon vcweb-icon icon-left' style='background:url(/static/images/famfamfam/control_play_blue.png);' alt=''></span>start round</a></li> + <span class='ui-icon vcweb-icon icon-left' style='background:url(/static/images/famfamfam/control_play_blue.png);' ></span>start round</a></li> {% endif %} <li><a class='confirm-experiment-action' name='advance_to_next_round' href='advance-to-next-round' title='Stops the current round if necessary and advances to the next round.'> - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/control_fastforward_blue.png);' alt=''></span>advance to next round</a></li> + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/control_fastforward_blue.png);' ></span>advance to next round</a></li> {% else %} <li><a class='confirm-experiment-action' name='setup_test_participants' href='setup-test-participants/20' title='Set up 20 participants'>Activate experiment with 20 participants</a></li> <li><a class='confirm-experiment-action' name='activate' href='activate' title='You must first activate an experiment before you can run it.'> - <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' alt=''></span>activate</a></li> + <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' ></span>activate</a></li> {% endif %} </ul> <br/> diff -r f107436c2323 -r 2005e4646d8d vcweb/core/templates/registration/login.html --- a/vcweb/core/templates/registration/login.html Sun Mar 27 01:43:13 2011 -0700 +++ b/vcweb/core/templates/registration/login.html Sun Mar 27 14:51:53 2011 -0700 @@ -16,7 +16,7 @@ {% block page %} -<form id='loginForm' name='loginForm' action='' method='post'> +<form id='loginForm' action='' method='post'> <h3>Returning User</h3> <p> Don't have an account or a first-time user? Please <a href='{% url core:register %}'>register first</a>. diff -r f107436c2323 -r 2005e4646d8d vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 01:43:13 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Sun Mar 27 14:51:53 2011 -0700 @@ -55,8 +55,8 @@ </div> {% endif %} -<div class='ui-state-highlight'> - <span class='icon-left ui-icon ui-icon-info'></span> +<div style='padding: 5px; margin: 8px 0px;' class='ui-state-highlight'> + <span class='icon-left ui-icon ui-icon-info'> </span> There are <b>{{ resource_level.value }}</b> trees left. </div> @@ -71,7 +71,7 @@ <form id='forestry-form' action='' method='post'> <div class='field'> <br/> - <label for='harvest-decision-id'>How many trees will you harvest this round? <br/><small><b>Choose a number between 0 and {{ max_harvest_decision }}</small></b>:</label> + <label for='harvest-decision-id'>How many trees will you harvest this round? <br/><span class='small-font bold'>Choose a number between 0 and {{ max_harvest_decision }}</span>:</label> <input id='harvest-decision-id' type="text" name='harvest_decision' class='required digits two-digits' maxlength='1'/> </div> <div class='field'> diff -r f107436c2323 -r 2005e4646d8d vcweb/forestry/templates/forestry/wait.html --- a/vcweb/forestry/templates/forestry/wait.html Sun Mar 27 01:43:13 2011 -0700 +++ b/vcweb/forestry/templates/forestry/wait.html Sun Mar 27 14:51:53 2011 -0700 @@ -53,7 +53,7 @@ Total group harvest decisions (B) </th> <th class='tooltip' title='The trees that regrew during this round.'>Trees regrown (C)</th> - <th class='tooltip' title='The number of trees available at the end of the round (A - B + C = D)'.>Final # trees (D)</th></tr> + <th class='tooltip' title='The number of trees available at the end of the round (A - B + C = D).'>Final # trees (D)</th></tr> </thead> <tbody> {% for harvest_round_data in participant_history %} diff -r f107436c2323 -r 2005e4646d8d vcweb/static/css/style.css --- a/vcweb/static/css/style.css Sun Mar 27 01:43:13 2011 -0700 +++ b/vcweb/static/css/style.css Sun Mar 27 14:51:53 2011 -0700 @@ -120,6 +120,9 @@ .small-font { font-size: 0.8em; } +.bold { + font-weight: bold; +} fieldset.small { font: 0.8em "Helvetica Neue", helvetica, arial, sans-serif; color: #666; |
From: <vir...@li...> - 2011-03-27 08:43:01
|
Subject: hg.virtualcommons 307 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/f107436c2323 changeset: 307:f107436c2323 user: Allen Lee <all...@as...> date: Sun Mar 27 01:43:13 2011 -0700 description: removing bounce effect (seems to be mucking the markup up) diffstat: vcweb/core/templates/monitor.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 6203f387de4d -r f107436c2323 vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sun Mar 27 01:38:18 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sun Mar 27 01:43:13 2011 -0700 @@ -66,7 +66,7 @@ case 'chat': break; case 'submit': - $('#participant_data_value_' + json.participant_data_value_pk).html(json.message).effect("highlight", {}, 5000).effect("bounce", { times: 3 }, 300); + $('#participant_data_value_' + json.participant_data_value_pk).html(json.message).effect("highlight", {}, 5000); addExperimentMessage("Participant " + json.participant_number + " (Group #" + json.participant_group + ") submit a harvest decision of " + json.message); break; |
From: <vir...@li...> - 2011-03-27 08:43:01
|
Subject: hg.virtualcommons 306 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/6203f387de4d changeset: 306:6203f387de4d user: Allen Lee <all...@as...> date: Sun Mar 27 01:38:18 2011 -0700 description: fixing broken reference to json.participant_data_value_pk diffstat: vcweb/core/templates/monitor.html | 2 +- vcweb/vcweb-tornadio.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r e3004186a758 -r 6203f387de4d vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sun Mar 27 01:30:48 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sun Mar 27 01:38:18 2011 -0700 @@ -66,7 +66,7 @@ case 'chat': break; case 'submit': - $('#participant_data_value_' + json.participant_round_data_value_pk).html(json.message).effect("highlight", {}, 5000); + $('#participant_data_value_' + json.participant_data_value_pk).html(json.message).effect("highlight", {}, 5000).effect("bounce", { times: 3 }, 300); addExperimentMessage("Participant " + json.participant_number + " (Group #" + json.participant_group + ") submit a harvest decision of " + json.message); break; diff -r e3004186a758 -r 6203f387de4d vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sun Mar 27 01:30:48 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sun Mar 27 01:38:18 2011 -0700 @@ -232,7 +232,7 @@ participant_group_rel = connection_manager.get_participant_group_relationship(self) if participant_group_rel is not None: group = participant_group_rel.group - message = "Participant %s (Group %s) connected." % (participant_group_rel.participant_number, group) + message = "Participant %s (%s) connected." % (participant_group_rel.participant_number, group) connection_manager.send_to_group(group, simplejson.dumps({ 'message' : message, |
From: <vir...@li...> - 2011-03-27 08:43:01
|
Subject: hg.virtualcommons 305 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/e3004186a758 changeset: 305:e3004186a758 user: Allen Lee <all...@as...> date: Sun Mar 27 01:30:48 2011 -0700 description: logging hack for testing purposes diffstat: vcweb/vcweb-tornadio.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diffs (24 lines): diff -r f7658f760af2 -r e3004186a758 vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sun Mar 27 01:25:22 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sun Mar 27 01:30:48 2011 -0700 @@ -7,11 +7,19 @@ import logging import simplejson +# FIXME: hack, configuring before django settings configures it so we can get things spit to the console.. vcweb.log +# seems to be missing these logging statements. +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s %(levelname)s %(message)s', + ) + sys.path.append(os.path.abspath('..')) os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' -from vcweb.core.models import ParticipantExperimentRelationship, ParticipantGroupRelationship, ChatMessage, Experimenter, Experiment, Participant +from vcweb.core.models import ParticipantExperimentRelationship, ParticipantGroupRelationship, ChatMessage, Experimenter, Experiment + logger = logging.getLogger(__name__) |
From: <vir...@li...> - 2011-03-27 08:25:07
|
Subject: hg.virtualcommons 304 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/f7658f760af2 changeset: 304:f7658f760af2 user: Allen Lee <all...@as...> date: Sun Mar 27 01:25:22 2011 -0700 description: adding tablesorter include diffstat: vcweb/core/templates/includes/tablesorter.html | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (6 lines): diff -r ed32f378213d -r f7658f760af2 vcweb/core/templates/includes/tablesorter.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vcweb/core/templates/includes/tablesorter.html Sun Mar 27 01:25:22 2011 -0700 @@ -0,0 +1,2 @@ +<link href="/static/css/tablesorter/style.css" rel="stylesheet" type="text/css" media="screen" /> +<script type="text/javascript" src="/static/js/jquery.tablesorter.min.js"></script> |
From: <vir...@li...> - 2011-03-27 08:16:08
|
Subject: hg.virtualcommons 303 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/ed32f378213d changeset: 303:ed32f378213d user: Allen Lee <all...@as...> date: Sun Mar 27 01:16:25 2011 -0700 description: participant harvest decision -> experimenter monitor page is now set up properly. might handle the participant history update by sending a refresh instead. diffstat: vcweb/core/models.py | 6 ++++++ vcweb/core/templates/monitor.html | 17 ++++++++++++----- vcweb/settings.py | 2 +- vcweb/vcweb-tornadio.py | 17 +++++++++++------ 4 files changed, 30 insertions(+), 12 deletions(-) diffs (133 lines): diff -r 5a23794eb40b -r ed32f378213d vcweb/core/models.py --- a/vcweb/core/models.py Sat Mar 26 23:50:57 2011 -0700 +++ b/vcweb/core/models.py Sun Mar 27 01:16:25 2011 -0700 @@ -1041,6 +1041,8 @@ participant_data_value, created = current_round_data.participant_data_values.get_or_create(parameter=parameter, participant_group_relationship=participant_group_relationship) participant_data_value.value = value + # FIXME: parameterize / make explicit? + participant_data_value.submitted = True participant_data_value.save() else: logger.warning("Unable to set data value %s on experiment %s for %s" % (value, experiment, parameter)) @@ -1128,6 +1130,10 @@ def current_round_data(self): return self.group.current_round_data + @property + def group_number(self): + return self.group.number + def __unicode__(self): return u"{0}: #{1} (in {2})".format(self.participant, self.participant_number, self.group) diff -r 5a23794eb40b -r ed32f378213d vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sat Mar 26 23:50:57 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sun Mar 27 01:16:25 2011 -0700 @@ -38,7 +38,6 @@ $('#statusDiv').show('fast'); $('#experimentData').show('fast'); $('#statusDiv [title]').qtip(qtipOptions); - if (round_data_count > 0) { $('#experimentData').accordion({ active: active_round_number - 1, @@ -46,6 +45,11 @@ }); } } + + function addExperimentMessage(message) { + $("#experiment-messages").append($("<div style='font-size: 0.8em;line-height:0.9em;padding:3px;' class='ui-state-highlight' />").append(message)); + } + $(function() { var experimentMessageDiv = document.getElementById('experiment-messages'); registerCallbacks({{ experiment.round_data.count }}, {{ experiment.current_round.sequence_number }}); @@ -57,11 +61,14 @@ var json = jQuery.parseJSON(json_string); switch (json.message_type) { case 'info': - $("#experiment-messages").append($("<div class='ui-state-highlight' />").append(json.message)); + addExperimentMessage(json.message); break; case 'chat': break; case 'submit': + $('#participant_data_value_' + json.participant_round_data_value_pk).html(json.message).effect("highlight", {}, 5000); + addExperimentMessage("Participant " + json.participant_number + " (Group #" + json.participant_group + + ") submit a harvest decision of " + json.message); break; default: } @@ -96,8 +103,8 @@ <div id='experiment-messages' class='experimenter-sidebar-messages notice ui-corner-all'> {% for group in experiment.groups.all %} {% for activity_log in group.current_round_activity_log %} - <div style='line-height: 0.9em;padding:3px;' class='ui-state-highlight'> - <small>{{activity_log}}</small> + <div style='font-size: 0.75em; line-height: 1.0em;padding:3px;' class='ui-state-highlight'> + {{activity_log}} </div> {% endfor %} {% endfor %} @@ -219,7 +226,7 @@ <div class='ui-state-highlight'> <a class='tooltip' name='{{chat_message.pk}}' title='{{chat_message.date_created}} {{chat_message.participant}}'> {{chat_message.date_created|date:"H:s"}}</a> | {{chat_message}} - <span class='ui-icon ui-icon-comment icon-right'></span> + <span class='ui-icon ui-icon-comment icon-right'></span> </div> {% endfor %} </div> diff -r 5a23794eb40b -r ed32f378213d vcweb/settings.py --- a/vcweb/settings.py Sat Mar 26 23:50:57 2011 -0700 +++ b/vcweb/settings.py Sun Mar 27 01:16:25 2011 -0700 @@ -65,7 +65,7 @@ TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', - 'django.template.loaders.eggs.load_template_source', + 'django.template.loaders.eggs.Loader', ) TEMPLATE_CONTEXT_PROCESSORS = ( diff -r 5a23794eb40b -r ed32f378213d vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sat Mar 26 23:50:57 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sun Mar 27 01:16:25 2011 -0700 @@ -224,7 +224,7 @@ participant_group_rel = connection_manager.get_participant_group_relationship(self) if participant_group_rel is not None: group = participant_group_rel.group - message = "Participant %s connected to group %s." % (participant_group_rel.participant_number, group) + message = "Participant %s (Group %s) connected." % (participant_group_rel.participant_number, group) connection_manager.send_to_group(group, simplejson.dumps({ 'message' : message, @@ -252,16 +252,21 @@ elif event.message_type == 'submit': # FIXME: need to set this up so that this forwards to the appropriate # experiment handler... - logger.debug("simplejson dump of submit event: " % - simplejson.dumps(event)) (participant_pk, experiment_pk) = connection_manager.get_participant_experiment_tuple(self) - participant = Participant.objects.get(pk=participant_pk) experiment = Experiment.objects.get(pk=experiment_pk) # sanity check, make sure this is a data round. if experiment.is_data_round_in_progress: - event.participant = participant experimenter_tuple = (experiment.experimenter.pk, experiment.pk) - connection_manager.send_to_experimenter(experimenter_tuple, event) + event.participant_pk = participant_pk + pgr_pk = event.participant_group_relationship_id + participant_group_relationship = ParticipantGroupRelationship.objects.get(pk=pgr_pk) + prdv = experiment.current_round_data.participant_data_values.get(participant_group_relationship__pk=pgr_pk) + event.participant_data_value_pk = prdv.pk + event.participant_number = participant_group_relationship.participant_number + event.participant_group = participant_group_relationship.group_number + json = simplejson.dumps(event.__dict__) + logger.debug("json is: %s" % json) + connection_manager.send_to_experimenter(experimenter_tuple, json) if experiment.all_participants_have_submitted: connection_manager.send_to_experimenter( experimenter_tuple, |
From: <vir...@li...> - 2011-03-27 06:50:42
|
Subject: hg.virtualcommons 302 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/5a23794eb40b changeset: 302:5a23794eb40b user: Allen Lee <all...@as...> date: Sat Mar 26 23:50:57 2011 -0700 description: updating schema, adding submitted boolean field to ParticipantRoundDataValues so that we can tell whether or not it's been user submitted. pushing hardcoded slovakia setup_test_participants into experiment, need to figure out a clean way to parameterize it with the number of students veronika wants to use... diffstat: vcweb/core/models.py | 27 +++++++++++++++++++++++++-- vcweb/core/templates/monitor.html | 17 ++++++++++------- vcweb/forestry/models.py | 4 +++- vcweb/forestry/templates/forestry/participate.html | 2 +- vcweb/forestry/templates/forestry/wait.html | 11 ++++++----- vcweb/vcweb-tornadio.py | 21 ++++++++++++--------- 6 files changed, 57 insertions(+), 25 deletions(-) diffs (218 lines): diff -r 87c41d851fd2 -r 5a23794eb40b vcweb/core/models.py --- a/vcweb/core/models.py Sat Mar 26 20:19:38 2011 -0700 +++ b/vcweb/core/models.py Sat Mar 26 23:50:57 2011 -0700 @@ -345,6 +345,27 @@ # return dynamic text based on current_round? return self.current_round.instructions + @property + def all_participants_have_submitted(self): + pdvs = self.current_round_data.participant_data_values + return pdvs.filter(submitted=False).count() == 0 + + ''' hardcoded defaults for the slovakia pretest ''' + def setup_test_participants(self, number_of_students=20, institution_name='Slovak Academy of Sciences', institution_url='http://www.sav.sk', email_suffix='sav.sk', test_password='test'): + if self.participants.count() > 0: + logger.debug("This experiment %s already has %d participants - aborting" + % (self, self.participants.count())) + return + (institution, created) = Institution.objects.get_or_create(name=institution_name, url=institution_url) + for i in xrange(1, number_of_students+1): + email = 's%d@%s' % (i, email_suffix) + u = User.objects.create_user(email, email, test_password) + u.first_name = 'Student' + u.last_name = u"%d" % i + u.save() + p = Participant.objects.create(user=u, institution=institution) + ParticipantExperimentRelationship.objects.create(participant=p, experiment=self, created_by=u) + def log(self, log_message): if log_message: self.activity_log.create(round_configuration=self.current_round, log_message=log_message) @@ -731,7 +752,8 @@ int_value = models.IntegerField(null=True) float_value = models.FloatField(null=True) boolean_value = models.NullBooleanField(null=True) - time_recorded = models.DateTimeField(auto_now_add=True) + date_created = models.DateTimeField(auto_now_add=True) + last_modified = models.DateTimeField(auto_now=True) @property def value(self): @@ -1097,7 +1119,7 @@ participant = models.ForeignKey(Participant, related_name='participant_group_relationships') group = models.ForeignKey(Group, related_name = 'participant_group_relationships') round_joined = models.ForeignKey(RoundConfiguration) - date_joined = models.DateTimeField(auto_now_add=True) + date_created = models.DateTimeField(auto_now_add=True) active = models.BooleanField(default=True) objects = ParticipantGroupRelationshipManager() @@ -1164,6 +1186,7 @@ class ParticipantRoundDataValue(DataValue): round_data = models.ForeignKey(RoundData, related_name='participant_data_values') participant_group_relationship = models.ForeignKey(ParticipantGroupRelationship, related_name='round_data_values') + submitted = models.BooleanField(default=False) def __init__(self, *args, **kwargs): super(ParticipantRoundDataValue, self).__init__(*args, **kwargs) diff -r 87c41d851fd2 -r 5a23794eb40b vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sat Mar 26 20:19:38 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sat Mar 26 23:50:57 2011 -0700 @@ -4,6 +4,7 @@ {% include "includes/experimenter.events.html" %} {% include "includes/socket.io.html" %} <script type='text/javascript'> + var qtipOptions = {position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'dark', tip: 'bottomMiddle'} }; function update(json) { if (json == Dajaxice.EXCEPTION) { console.error("dajaxice error: " + json); @@ -36,6 +37,7 @@ $('#statusSpinner').hide('fast'); $('#statusDiv').show('fast'); $('#experimentData').show('fast'); + $('#statusDiv [title]').qtip(qtipOptions); if (round_data_count > 0) { $('#experimentData').accordion({ @@ -44,7 +46,6 @@ }); } } - var qtipOptions = {position: { corner: {target: 'topMiddle', tooltip: 'bottomMiddle'}}, style: { name: 'dark', tip: 'bottomMiddle'} }; $(function() { var experimentMessageDiv = document.getElementById('experiment-messages'); registerCallbacks({{ experiment.round_data.count }}, {{ experiment.current_round.sequence_number }}); @@ -126,19 +127,21 @@ {% block status %} <fieldset class='small ui-corner-all'> <legend>round status</legend> - <ul id='actions' class='actions tooltip' title='Use the links to start/end a round, advance to the next round, or download data. '> + <ul id='actions' class='actions'> {% if experiment.is_active %} {% if experiment.is_round_in_progress %} - <li><a class='confirm-experiment-action' name='end_round' href='end-round'> + <li><a class='confirm-experiment-action' name='end_round' href='end-round' title='Stops the current round.'> <span class='vcweb-icon icon-left ui-icon' style='background: url(/static/images/famfamfam/control_stop_blue.png);' alt=''></span>end round</a></li> {% else %} - <li><a class='confirm-experiment-action' name='start_round' href='start-round'> + <li><a class='confirm-experiment-action' name='start_round' href='start-round' title='Starts the round.'> <span class='ui-icon vcweb-icon icon-left' style='background:url(/static/images/famfamfam/control_play_blue.png);' alt=''></span>start round</a></li> {% endif %} - <li><a class='confirm-experiment-action' name='advance_to_next_round' href='advance-to-next-round'> + <li><a class='confirm-experiment-action' name='advance_to_next_round' href='advance-to-next-round' title='Stops the current round if necessary and advances to the next round.'> <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/control_fastforward_blue.png);' alt=''></span>advance to next round</a></li> {% else %} - <li><a class='confirm-experiment-action' name='activate' href='activate'> + <li><a class='confirm-experiment-action' name='setup_test_participants' + href='setup-test-participants/20' title='Set up 20 participants'>Activate experiment with 20 participants</a></li> + <li><a class='confirm-experiment-action' name='activate' href='activate' title='You must first activate an experiment before you can run it.'> <span class='vcweb-icon ui-icon icon-left' style='background:url(/static/images/famfamfam/cog_go.png);' alt=''></span>activate</a></li> {% endif %} </ul> @@ -199,7 +202,7 @@ </a> </td> <td>{{ participant_data_value.parameter.label }}</td> - <td>{{ participant_data_value.value }}</td> + <td id='participant_data_value_{{participant_data_value.pk}}'>{{ participant_data_value.value }}</td> <td>{{ participant_data_value.parameter.type }}</td> </tr> {% endfor %} diff -r 87c41d851fd2 -r 5a23794eb40b vcweb/forestry/models.py --- a/vcweb/forestry/models.py Sat Mar 26 20:19:38 2011 -0700 +++ b/vcweb/forestry/models.py Sat Mar 26 23:50:57 2011 -0700 @@ -1,4 +1,5 @@ -from vcweb.core.models import ExperimentMetadata, Parameter, ParticipantGroupRelationship, ParticipantRoundDataValue +from django.contrib.auth.models import User +from vcweb.core.models import ExperimentMetadata, Parameter, ParticipantExperimentRelationship, ParticipantGroupRelationship, ParticipantRoundDataValue, Participant, Institution from vcweb.core import signals from celery.decorators import task import logging @@ -10,6 +11,7 @@ check all forestry experiments. ''' + # returns GroupRoundDataValue. def get_resource_level(group=None, round_data=None): return group.get_data_value(parameter=get_resource_level_parameter(), round_data=round_data) diff -r 87c41d851fd2 -r 5a23794eb40b vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Sat Mar 26 20:19:38 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Sat Mar 26 23:50:57 2011 -0700 @@ -60,7 +60,7 @@ There are <b>{{ resource_level.value }}</b> trees left. </div> -{% if harvest_decision %} +{% if harvest_decision.submitted %} <div class='alert alertIcon ui-corner-all'> You have already made a harvest decision of <b>{{ harvest_decision.value }}</b>. You may change your decision until the experimenter ends the round. diff -r 87c41d851fd2 -r 5a23794eb40b vcweb/forestry/templates/forestry/wait.html --- a/vcweb/forestry/templates/forestry/wait.html Sat Mar 26 20:19:38 2011 -0700 +++ b/vcweb/forestry/templates/forestry/wait.html Sat Mar 26 23:50:57 2011 -0700 @@ -14,7 +14,6 @@ switch (json.message_type) { case 'update': console.log("updating data"); - $('#round_' + json.round_sequence_number); break; case 'goto': console.log("going to " + json.url); @@ -58,7 +57,7 @@ </thead> <tbody> {% for harvest_round_data in participant_history %} - <tr id='round_{{harvest_round_data.round_configuration.sequence_number}}'> + <tr> <td> {% if harvest_round_data.round_in_progress %} <div id='round-in-progress' style='line-height: 0.9em;' class='alert alertIcon ui-corner-all tooltip' title='This round is still in progress so only your harvest decision for this round is being shown.'> @@ -74,9 +73,11 @@ 0 {%endif%} </td> - <td>{{harvest_round_data.group_harvest.value}}</td> - <td>{{harvest_round_data.group_regrowth.value}}</td> - <td>{{harvest_round_data.final_number_of_trees}}</td> + {% with sequence_number=harvest_round_data.round_configuration.sequence_number %} + <td id='group_harvest_{{sequence_number}}'>{{harvest_round_data.group_harvest.value}}</td> + <td id='group_regrowth_{{sequence_number}}'>{{harvest_round_data.group_regrowth.value}}</td> + <td id='final_number_of_trees_{{sequence_number}}'>{{harvest_round_data.final_number_of_trees}}</td> + {% endwith %} </tr> {% endfor %} </tbody> diff -r 87c41d851fd2 -r 5a23794eb40b vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sat Mar 26 20:19:38 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sat Mar 26 23:50:57 2011 -0700 @@ -255,16 +255,19 @@ logger.debug("simplejson dump of submit event: " % simplejson.dumps(event)) (participant_pk, experiment_pk) = connection_manager.get_participant_experiment_tuple(self) - event.participant = Participant.objects.get(pk=participant_pk) + participant = Participant.objects.get(pk=participant_pk) experiment = Experiment.objects.get(pk=experiment_pk) - connection_manager.send_to_experimenter( - (experiment.experimenter.pk, experiment.pk), - simplejson.dumps(event)) - - - - - +# sanity check, make sure this is a data round. + if experiment.is_data_round_in_progress: + event.participant = participant + experimenter_tuple = (experiment.experimenter.pk, experiment.pk) + connection_manager.send_to_experimenter(experimenter_tuple, event) + if experiment.all_participants_have_submitted: + connection_manager.send_to_experimenter( + experimenter_tuple, + info_json('All participants have submitted a harvest decision.')) + else: + logger.debug("No data round in progress, received late submit event: %s" % event) elif event.message_type == 'chat': participant_group_relationship = connection_manager.get_participant_group_relationship(self) |
From: <vir...@li...> - 2011-03-27 03:19:30
|
Subject: hg.virtualcommons 301 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/87c41d851fd2 changeset: 301:87c41d851fd2 user: Allen Lee <all...@as...> date: Sat Mar 26 20:19:38 2011 -0700 description: reordering initial_data.json entities, otherwise postgres sync fails changing type -> message_type for consistency diffstat: vcweb/core/fixtures/initial_data.json | 41 ++++++++++---------- vcweb/core/templates/includes/experimenter.events.html | 2 +- vcweb/core/templates/includes/participant.events.html | 2 +- vcweb/forestry/fixtures/initial_data.json | 12 +----- vcweb/vcweb-tornadio.py | 12 +++--- 5 files changed, 29 insertions(+), 40 deletions(-) diffs (154 lines): diff -r 740dcdc8a809 -r 87c41d851fd2 vcweb/core/fixtures/initial_data.json --- a/vcweb/core/fixtures/initial_data.json Sat Mar 26 19:28:51 2011 -0700 +++ b/vcweb/core/fixtures/initial_data.json Sat Mar 26 20:19:38 2011 -0700 @@ -8,6 +8,26 @@ "description": null } }, + { + "pk": 1, + "model": "auth.user", + "fields": { + "username": "alee", + "first_name": "Allen", + "last_name": "Lee", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2010-07-29 21:36:40", + "groups": [ + 1 + ], + "user_permissions": [], + "password": "sha1$90c58$70c01e2b7ba1c997b04bafe03d99215c3205a9ee", + "email": "all...@as...", + "date_joined": "2010-07-29 21:36:40" + } + }, { "pk": 1, "model": "core.experimenter", @@ -33,26 +53,5 @@ "name": "Participants", "permissions": [] } - }, - { - "pk": 1, - "model": "auth.user", - "fields": { - "username": "alee", - "first_name": "Allen", - "last_name": "Lee", - "is_active": true, - "is_superuser": true, - "is_staff": true, - "last_login": "2010-07-29 21:36:40", - "groups": [ - 1 - ], - "user_permissions": [], - "password": "sha1$90c58$70c01e2b7ba1c997b04bafe03d99215c3205a9ee", - "email": "all...@as...", - "date_joined": "2010-07-29 21:36:40" - } } - ] diff -r 740dcdc8a809 -r 87c41d851fd2 vcweb/core/templates/includes/experimenter.events.html --- a/vcweb/core/templates/includes/experimenter.events.html Sat Mar 26 19:28:51 2011 -0700 +++ b/vcweb/core/templates/includes/experimenter.events.html Sat Mar 26 20:19:38 2011 -0700 @@ -25,7 +25,7 @@ event_type = "experimenter"; } return { - "type": event_type, + "message_type": event_type, "experimenter_id": {{request.user.experimenter.pk}}, "experiment_id": {{experiment.pk}}, "message": message diff -r 740dcdc8a809 -r 87c41d851fd2 vcweb/core/templates/includes/participant.events.html --- a/vcweb/core/templates/includes/participant.events.html Sat Mar 26 19:28:51 2011 -0700 +++ b/vcweb/core/templates/includes/participant.events.html Sat Mar 26 20:19:38 2011 -0700 @@ -10,7 +10,7 @@ event_type = "chat"; } return { - "type": event_type, + "message_type": event_type, {% if participant_group_relationship %} "participant_group_relationship_id": {{participant_group_relationship.pk}}, {% else %} diff -r 740dcdc8a809 -r 87c41d851fd2 vcweb/forestry/fixtures/initial_data.json --- a/vcweb/forestry/fixtures/initial_data.json Sat Mar 26 19:28:51 2011 -0700 +++ b/vcweb/forestry/fixtures/initial_data.json Sat Mar 26 20:19:38 2011 -0700 @@ -14,16 +14,6 @@ "pk": 1 }, { - "pk": 2, - "model": "core.experimenter", - "fields": { - "approved": true, - "user": 12, - "failed_password_attempts": 0, - "institution": 1 - } - }, - { "fields": { "authentication_code": "TEST_FORESTRY", "current_round_elapsed_time": 0, @@ -31,7 +21,7 @@ "duration": "1h", "experiment_configuration": 1, "experiment_metadata": 1, - "experimenter": 2, + "experimenter": 1, "is_experimenter_driven": true, "start_date_time": null, "status": "INACTIVE", diff -r 740dcdc8a809 -r 87c41d851fd2 vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sat Mar 26 19:28:51 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sat Mar 26 20:19:38 2011 -0700 @@ -189,16 +189,16 @@ def on_message(self, message): event = to_event(message) logger.debug("%s received message %s" % (self, message)) - if event.type == 'connect': + if event.message_type == 'connect': connection_manager.add_experimenter(self, event.experimenter_id, event.experiment_id) - elif event.type == 'refresh': + elif event.message_type == 'refresh': experiment_id = event.experiment_id experimenter_id = event.experimenter_id experiment = Experiment.objects.get(pk=experiment_id) connection_manager.send_refresh(self, experiment, experimenter_id) logger.debug("pinging back to experimenter") self.send(info_json("Refreshed all participants")) - elif event.type == 'goto': + elif event.message_type == 'goto': experiment_id = event.experiment_id experiment = Experiment.objects.get(pk=experiment_id) url = event.url @@ -247,9 +247,9 @@ logger.debug("received message %s from handler %s" % (message, self)) event = to_event(message) # FIXME: on_message / connect should add them to the list of participants - if 'connect' in event.type: + if 'connect' in event.message_type: return - elif event.type == 'submit': + elif event.message_type == 'submit': # FIXME: need to set this up so that this forwards to the appropriate # experiment handler... logger.debug("simplejson dump of submit event: " % @@ -266,7 +266,7 @@ - elif event.type == 'chat': + elif event.message_type == 'chat': participant_group_relationship = connection_manager.get_participant_group_relationship(self) current_round_data = participant_group_relationship.group.experiment.current_round_data chat_message = ChatMessage.objects.create(participant_group_relationship=participant_group_relationship, |
From: <vir...@li...> - 2011-03-27 02:28:38
|
Subject: hg.virtualcommons 300 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/740dcdc8a809 changeset: 300:740dcdc8a809 user: Allen Lee <all...@as...> date: Sat Mar 26 19:28:51 2011 -0700 description: RoundConfiguration.get_parameter_value now takes and returns a default argument (which defaults to None if it isn't passed in) if the parameter doesn't exist for the given round. Starting to wire together experimenter <-> participant synchronization in the wait/monitor pages diffstat: vcweb/core/models.py | 4 +- vcweb/core/templates/monitor.html | 11 +++-- vcweb/forestry/models.py | 2 +- vcweb/forestry/templates/forestry/participate.html | 2 +- vcweb/forestry/templates/forestry/wait.html | 6 ++- vcweb/settings.py | 7 ++- vcweb/vcweb-tornadio.py | 40 +++++++++++++++++-- 7 files changed, 56 insertions(+), 16 deletions(-) diffs (198 lines): diff -r 520a05b9289c -r 740dcdc8a809 vcweb/core/models.py --- a/vcweb/core/models.py Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/core/models.py Sat Mar 26 19:28:51 2011 -0700 @@ -579,11 +579,11 @@ parameter_value.value = value parameter_value.save() - def get_parameter_value(self, name): + def get_parameter_value(self, name, default=None): try: return self.round_parameter_values.get(parameter__name=name).value except RoundParameterValue.DoesNotExist: - return None + return default def get_debriefing(self, participant_id=None, **kwargs): return self.templatize(self.debriefing, participant_id, kwargs) diff -r 520a05b9289c -r 740dcdc8a809 vcweb/core/templates/monitor.html --- a/vcweb/core/templates/monitor.html Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/core/templates/monitor.html Sat Mar 26 19:28:51 2011 -0700 @@ -58,12 +58,15 @@ case 'info': $("#experiment-messages").append($("<div class='ui-state-highlight' />").append(json.message)); break; + case 'chat': + break; + case 'submit': + break; default: } scrollToBottom(experimentMessageDiv); }); - $('.tooltip').qtip(qtipOptions); - $('a[title]').not('.tooltip').qtip(qtipOptions); + $('[title]').qtip(qtipOptions); $('#refreshAllParticipants').click(function(evt) { console.log("sending refresh event"); s.send(createRefreshEvent()); @@ -212,8 +215,8 @@ {% for chat_message in round_data.chat_messages.all %} <div class='ui-state-highlight'> <a class='tooltip' name='{{chat_message.pk}}' title='{{chat_message.date_created}} {{chat_message.participant}}'> - <span class='ui-icon ui-icon-comment icon-right'></span> {{chat_message.date_created|date:"H:s"}}</a> | - {{chat_message}} + {{chat_message.date_created|date:"H:s"}}</a> | {{chat_message}} + <span class='ui-icon ui-icon-comment icon-right'></span> </div> {% endfor %} </div> diff -r 520a05b9289c -r 740dcdc8a809 vcweb/forestry/models.py --- a/vcweb/forestry/models.py Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/forestry/models.py Sat Mar 26 19:28:51 2011 -0700 @@ -107,7 +107,7 @@ practice or regular round, set up resource levels and participant harvest decision parameters ''' - if round_configuration.get_parameter_value('reset.resource_level'): + if round_configuration.get_parameter_value('reset.resource_level', default=False): for group in experiment.groups.all(): ''' set resource level to default ''' set_resource_level(group, round_configuration.get_parameter_value('initial.resource_level')) diff -r 520a05b9289c -r 740dcdc8a809 vcweb/forestry/templates/forestry/participate.html --- a/vcweb/forestry/templates/forestry/participate.html Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/forestry/templates/forestry/participate.html Sat Mar 26 19:28:51 2011 -0700 @@ -34,7 +34,7 @@ $('#forestry-form').submit(function() { $(this).attr('disabled', true); harvestDecisionValue = $('#harvest-decision-id').val(); - s.send(createSubmitEvent($('#harvest-decision-id').val())); + s.send(createSubmitEvent(harvestDecisionValue)); return true; }); }); diff -r 520a05b9289c -r 740dcdc8a809 vcweb/forestry/templates/forestry/wait.html --- a/vcweb/forestry/templates/forestry/wait.html Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/forestry/templates/forestry/wait.html Sat Mar 26 19:28:51 2011 -0700 @@ -12,6 +12,10 @@ s.on('message', function(json_string) { var json = jQuery.parseJSON(json_string); switch (json.message_type) { + case 'update': + console.log("updating data"); + $('#round_' + json.round_sequence_number); + break; case 'goto': console.log("going to " + json.url); window.location.href = json.url; @@ -54,7 +58,7 @@ </thead> <tbody> {% for harvest_round_data in participant_history %} - <tr> + <tr id='round_{{harvest_round_data.round_configuration.sequence_number}}'> <td> {% if harvest_round_data.round_in_progress %} <div id='round-in-progress' style='line-height: 0.9em;' class='alert alertIcon ui-corner-all tooltip' title='This round is still in progress so only your harvest decision for this round is being shown.'> diff -r 520a05b9289c -r 740dcdc8a809 vcweb/settings.py --- a/vcweb/settings.py Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/settings.py Sat Mar 26 19:28:51 2011 -0700 @@ -2,9 +2,12 @@ import os.path import logging +LOG_FILENAME = 'vcweb.log' + logging.basicConfig( level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', + filename=LOG_FILENAME, ) DEBUG = True @@ -60,8 +63,8 @@ # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - 'django.template.loaders.app_directories.load_template_source', + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', 'django.template.loaders.eggs.load_template_source', ) diff -r 520a05b9289c -r 740dcdc8a809 vcweb/vcweb-tornadio.py --- a/vcweb/vcweb-tornadio.py Sat Mar 26 01:46:59 2011 -0700 +++ b/vcweb/vcweb-tornadio.py Sat Mar 26 19:28:51 2011 -0700 @@ -7,13 +7,14 @@ import logging import simplejson -logger = logging.getLogger(__name__) - sys.path.append(os.path.abspath('..')) os.environ['DJANGO_SETTINGS_MODULE'] = 'vcweb.settings' -from vcweb.core.models import ParticipantExperimentRelationship, ParticipantGroupRelationship, ChatMessage, Experimenter, Experiment +from vcweb.core.models import ParticipantExperimentRelationship, ParticipantGroupRelationship, ChatMessage, Experimenter, Experiment, Participant + +logger = logging.getLogger(__name__) + def info_json(message): return simplejson.dumps({'message_type': 'info', 'message': message}) @@ -21,6 +22,11 @@ def goto_json(url): return simplejson.dumps({'message_type': 'goto', 'url': url}) +class Message(object): + def __init__(self, message_type='info', **kwargs): + self.message_type = message_type + self.__dict__.update(**kwargs) + ''' Manages socket.io connections to tornadio. ''' @@ -66,6 +72,19 @@ logger.debug("Didn't find connection %s in connection map %s." % (connection, self.connection_to_participant)) return None + def get_experiment(self, connection): + if connection in self.connection_to_participant: + experiment_pk = self.connection_to_participant[connection][1] + return Experiment.objects.get(pk=experiment_pk) + else: + return None + + def get_participant_experiment_tuple(self, connection): + if connection in self.connection_to_participant: + return self.connection_to_participant[connection] + else: + return None + def add_participant(self, auth_token, connection, participant_experiment_relationship): participant_tuple = (participant_experiment_relationship.participant.pk, participant_experiment_relationship.experiment.pk) @@ -233,8 +252,19 @@ elif event.type == 'submit': # FIXME: need to set this up so that this forwards to the appropriate # experiment handler... - payload = event.message - logger.debug("payload is: " % payload) + logger.debug("simplejson dump of submit event: " % + simplejson.dumps(event)) + (participant_pk, experiment_pk) = connection_manager.get_participant_experiment_tuple(self) + event.participant = Participant.objects.get(pk=participant_pk) + experiment = Experiment.objects.get(pk=experiment_pk) + connection_manager.send_to_experimenter( + (experiment.experimenter.pk, experiment.pk), + simplejson.dumps(event)) + + + + + elif event.type == 'chat': participant_group_relationship = connection_manager.get_participant_group_relationship(self) |
From: <vir...@li...> - 2011-03-26 08:47:08
|
Subject: hg.virtualcommons 299 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/520a05b9289c changeset: 299:520a05b9289c user: Allen Lee <all...@as...> date: Sat Mar 26 01:46:59 2011 -0700 description: fixing RoundParameterValue.DoesNotExist error when reset.resource_level isn't present. Adding transfer_participants function to transfer one experiment's participants to another, debating whether or not to automatically tie it in with a clone() diffstat: vcweb/core/models.py | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diffs (30 lines): diff -r cec126dc8e0d -r 520a05b9289c vcweb/core/models.py --- a/vcweb/core/models.py Sat Mar 26 00:41:07 2011 -0700 +++ b/vcweb/core/models.py Sat Mar 26 01:46:59 2011 -0700 @@ -469,8 +469,12 @@ ) def transfer_participants(self, experiment): - pass - + if experiment.participants.count() == 0: + for participant in self.participants.all(): + ParticipantExperimentRelationship.objects.create(participant=participant, + experiment=experiment, created_by=self.experimenter.user) + else: + logger.warning("Tried to transfer participants to an experiment %s that already had participants %s" % (experiment, experiment.participants.all())) def __unicode__(self): return u"%s #%s | %s" % (self.experiment_metadata.title, self.pk, self.experimenter) @@ -576,7 +580,10 @@ parameter_value.save() def get_parameter_value(self, name): - return self.round_parameter_values.get(parameter__name=name).value + try: + return self.round_parameter_values.get(parameter__name=name).value + except RoundParameterValue.DoesNotExist: + return None def get_debriefing(self, participant_id=None, **kwargs): return self.templatize(self.debriefing, participant_id, kwargs) |
From: <vir...@li...> - 2011-03-26 07:41:08
|
Subject: hg.virtualcommons 298 details: http://virtualcommons.hg.sourceforge.net:8000/hgroot/virtualcommons/virtualcommons/hgrepo/v/vi/virtualcommons/virtualcommons/rev/cec126dc8e0d changeset: 298:cec126dc8e0d user: Allen Lee <all...@as...> date: Sat Mar 26 00:41:07 2011 -0700 description: updating settings to use DATABASES dict instead of deprecated DATABASE_foo. TODO: use django.contrib.staticfiles to reference static files diffstat: vcweb/README | 6 ++---- vcweb/core/models.py | 4 ++++ vcweb/settings.py | 13 ++++++------- vcweb/settings_production.py | 14 ++++++++------ 4 files changed, 20 insertions(+), 17 deletions(-) diffs (79 lines): diff -r 238d9a46e9cc -r cec126dc8e0d vcweb/README --- a/vcweb/README Fri Mar 25 01:02:41 2011 -0700 +++ b/vcweb/README Sat Mar 26 00:41:07 2011 -0700 @@ -10,12 +10,10 @@ 2. easy_install pip 3. pip install virtualenv (if you don't want to muck up your base python system) 4. pip install fabric -5. fab setup (change default settings in fabfile.py as necessary; eventually I -should make this configurable) +5. fab setup (change default settings in fabfile.py as necessary; eventually I should make this configurable) 6. fab syncdb 7. fab server (in one terminal) -8. fab tornado (in another terminal) if you want to run vcweb w/ server push -enabled. +8. fab tornadio (in another terminal) if you want to run vcweb w/ server push enabled. To start up celeryd and celerybeat diff -r 238d9a46e9cc -r cec126dc8e0d vcweb/core/models.py --- a/vcweb/core/models.py Fri Mar 25 01:02:41 2011 -0700 +++ b/vcweb/core/models.py Sat Mar 26 00:41:07 2011 -0700 @@ -468,6 +468,10 @@ status=Experiment.INACTIVE ) + def transfer_participants(self, experiment): + pass + + def __unicode__(self): return u"%s #%s | %s" % (self.experiment_metadata.title, self.pk, self.experimenter) diff -r 238d9a46e9cc -r cec126dc8e0d vcweb/settings.py --- a/vcweb/settings.py Fri Mar 25 01:02:41 2011 -0700 +++ b/vcweb/settings.py Sat Mar 26 00:41:07 2011 -0700 @@ -18,13 +18,12 @@ MANAGERS = ADMINS -DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. -DATABASE_NAME = 'vcweb.db' # Or path to database file if using sqlite3. -DATABASE_USER = '' # Not used with sqlite3. -DATABASE_PASSWORD = '' # Not used with sqlite3. -DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. -DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. - +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'vcweb.db', + } + } # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. diff -r 238d9a46e9cc -r cec126dc8e0d vcweb/settings_production.py --- a/vcweb/settings_production.py Fri Mar 25 01:02:41 2011 -0700 +++ b/vcweb/settings_production.py Sat Mar 26 00:41:07 2011 -0700 @@ -9,12 +9,14 @@ MANAGERS = ADMINS -DATABASE_ENGINE = 'postgresql_psycopg2' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. -DATABASE_NAME = 'vcweb' # Or path to database file if using sqlite3. -DATABASE_USER = 'vcweb' # Not used with sqlite3. -DATABASE_PASSWORD = 'CUSTOMIZE_ME' # Not used with sqlite3. -DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. -DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'vcweb', + 'USER': 'vcweb', + 'PASSWORD': 'CUSTOMIZE_ME', + } + } # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name |