diff --git a/ui/src/main/resources/PhenoTips/PCHome.xml b/ui/src/main/resources/PhenoTips/PCHome.xml index ecb8ad53..784b1a99 100644 --- a/ui/src/main/resources/PhenoTips/PCHome.xml +++ b/ui/src/main/resources/PhenoTips/PCHome.xml @@ -49,7 +49,7 @@ $xwiki.ssx.use('PhenoTips.PCHome')## <div class="title-container half-width"> <h1>PhenomeCentral</h1> <p>A hub for secure data sharing within the rare disorder community</p> - <div class="buttons"><a class="user-action sign-up" id="launch-register" href="$xwiki.getURL('PhenomeCentral.register')">Sign up</a> <a class="user-action login" id="launch-login" href="$xwiki.getURL('PhenomeCentral.login')">Login</a> <a class="user-action about" href="$xwiki.getURL('PhenomeCentral.About')">Read more...</a></div> + <div class="buttons"><a class="user-action sign-up" id="launch-register" href="$xwiki.getURL('PhenomeCentral.', 'register')">Sign up</a> <a class="user-action login" id="launch-login" href="$xwiki.getURL('PhenomeCentral.login')">Login</a> <a class="user-action about" href="$xwiki.getURL('PhenomeCentral.About')">Read more...</a></div> </div> <div class="clearfloats"></div> </div> diff --git a/ui/src/main/resources/PhenoTips/Translations.xml b/ui/src/main/resources/PhenoTips/Translations.xml new file mode 100644 index 00000000..5a352501 --- /dev/null +++ b/ui/src/main/resources/PhenoTips/Translations.xml @@ -0,0 +1,98 @@ + + + + + + PhenoTips + Translations + + + 0 + PhenoTips.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1393352581000 + 1393882772000 + 1393882772000 + 1.1 + Translations + + + + false + xwiki/2.1 + true + patient.livetable.doc.name=Report name +patient.livetable.doc.creator=Reported by +patient.livetable.doc.author=Last modified by +patient.livetable.doc.creationDate=Report date +patient.livetable.doc.date=Last modification date +patient.livetable.last_name=Last name +patient.livetable.first_name=First name +patient.livetable.gender=Gender +patient.livetable.date_of_birth=Date of birth +patient.livetable.health_card=Provincial health card # +patient.livetable.relative_of=Relative of +patient.livetable._actions= +patient.livetable.emptyvalue=- +patient.livetable.p_id=Identifier +patient.livetable.congenital=Congenital +patient.livetable.sex=Sex +patient.livetable.global_age_of_onset=Onset +patient.livetable.phenotype=Phenotype +patient.livetable.negative_phenotype=Negative phenotype +patient.livetable.omim_id=Disorder +patient.livetable.identifier=Identifier +patient.livetable.external_id=Identifier +patient.livetable.global_mode_of_inheritance=Global mode of inheritance +patient.livetable.unaffected=Clinically normal +patient.livetable.exam_date=Exam Date +patient.livetable.relative=Relative +patient.livetable.consanguinity=Consanguinity +patient.livetable.omim_id=OMIM disorder +patient.livetable.gestation=Gestation at delivery (weeks) +patient.livetable.proband=Proband +patient.livetable.in_vitro=In vitro +patient.livetable.maternal_ethnicity=Maternal ethnicity +patient.livetable.paternal_ethnicity=Paternal ethnicity +patient.livetable.family_of=Pedigree number +patient.livetable.miscarriages=Parents with at least 3 miscarriages + +admin.phenotips=PhenoTips +admin.phenotips.description=Phenotype data settings. +admin.welcome=Welcome message +admin.tablesconfig=Data tables +admin.dataformats=Data formats +admin.menuconfig=Menu configuration +admin.formconfig=Patient form structure +admin.mapping=Phenotypes displayed by default +admin.ontology=Ontology index +admin.workgroups=Work groups +admin.studies=Studies +admin.pendingusers=Pending Users + +saveandview=Save + +phenotips.profile.preferences=PhenoTips preferences +phenotips.profile.preferences.mapping=Preferred mapping + diff --git a/ui/src/main/resources/PhenomeCentral/RegistrationWiki.xml b/ui/src/main/resources/PhenomeCentral/RegistrationWiki.xml new file mode 100644 index 00000000..d9a275bb --- /dev/null +++ b/ui/src/main/resources/PhenomeCentral/RegistrationWiki.xml @@ -0,0 +1,1167 @@ + + + + + + PhenomeCentral + RegistrationWiki + + + 0 + XWiki.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1394145490000 + 1394149207000 + 1394149207000 + 1.1 + RegistrationWiki + + + + false + xwiki/2.0 + true + + PhenomeCentral.RegistrationWiki + + + + + + + + + 0 + defaultRedirect + 7 + 0 + Redirect here after registration + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + 0 + heading + 1 + 0 + Registration page heading + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + 0 + liveValidation_defaultFieldOkMessage + 4 + 0 + Default field okay message + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + + 0 + checkbox + + liveValidation_enabled + 3 + Enable Javascript field validation + 0 + + + com.xpn.xwiki.objects.classes.BooleanClass + + + + 0 + checkbox + + loginButton_autoLogin_enabled + 6 + Enable automatic login + 0 + + + com.xpn.xwiki.objects.classes.BooleanClass + + + + 0 + checkbox + + loginButton_enabled + 5 + Enable login button + 0 + + + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + PureText + registrationSuccessMessage + 9 + 0 + Registration Successful Message + 12 + 40 + 0 + + + com.xpn.xwiki.objects.classes.TextAreaClass + + + + 0 + checkbox + + requireCaptcha + 8 + Require captcha to register + 0 + + + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + PureText + welcomeMessage + 2 + 0 + Welcome message + 12 + 40 + 0 + + + com.xpn.xwiki.objects.classes.TextAreaClass + + + + + XWiki.XWikiRights + + + + + + + + + 1 + 0 + select + allow + allow + 4 + Allow/Deny + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + 0 + input + 1 + groups + 1 + 1 + Groups + 0 + + 5 + 0 + com.xpn.xwiki.objects.classes.GroupsClass + + + 0 + 0 + select + 1 + levels + 2 + Levels + 0 + + 3 + 0 + com.xpn.xwiki.objects.classes.LevelsClass + + + 0 + 0 + input + 1 + users + 3 + 1 + Users + 0 + + 5 + 0 + com.xpn.xwiki.objects.classes.UsersClass + + + PhenomeCentral.RegistrationWiki + 0 + XWiki.XWikiRights + cf6b2353-d01f-41f5-93d8-ab55c77db4f0 + + 1 + + + XWiki.XWikiAllGroup,xwiki:XWiki.XWikiAllGroup + + + view + + + XWiki.XWikiGuest + + + {{velocity}} +##--- +$xwiki.ssx.use('data.WebHome')## +$xwiki.jsfx.use('uicomponents/widgets/validation/uniquenessvalidation.js')## +#set($documentName = 'PhenomeCentral.RegistrationWiki') +##--- +## These are defined in other places around XWiki, changing them here will result in undefined behavior. +#set($redirectParam = 'xredirect') +#set($userSpace = 'XWiki.') +#set($loginPage = 'XWiki.XWikiLogin') +#set($loginAction = 'loginsubmit') +## +## +## Security measure: +## If this document is changed such that it must have programming permission in order to run, change this to false. +#set($sandbox = true) +## +## Load the configuration from a seperate document. +#loadConfig('XWiki.RegistrationConfig') +## +## Defines what server generated error messages should look like +## The error message when a field is entered incorrectly +#set($failureMessageParams = { 'class' : 'LV_validation_message LV_invalid'}) +## 'LV_validation_message LV_invalid' depends on this: +$xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', true) +## +## The * next to the fields to denote they are mandatory. +#set($fieldMandatoryStar = { 'class' : 'xRequired'}) +## +#* + * You may include this document in other documents using {{include document="XWiki.Registration"/}} + * To specify that the user is invited and should be allowed to register even if Guest does not have permission to + * register, set $invited to true. NOTE: The including script must have programming permission to do this. + * + * To specify some code which should run after registration is successfully completed, set + * $doAfterRegistration to a define block of velocity code like so: + * #define($doAfterRegistration) + * some code + * #end + * Output from running this code will not be printed. + * + * The fields which will be seen on the registration page are defined here. + * $fields is an array and each field is a Map. The names shown below are Map keys. + * + * Each field must have: + * name - this is the name of the field, it will be the value for "name" and "id" + * + * Each field may have: + * label - this String will be written above the field. + * + * tag - the HTML tag which will be created, default is <input>, may also be a non form tag such as <img> + * + * params - a Map, each key value pair will be in the html tag. eg: {"size" : "30"} becomes <input size=30... + * + * validate a Map describing how to validate the field, validation is done in javascript then redone in velocity + * | for security and because not everyone has javascript. + * | + * +-mandatory (Optional) - Will fail if the field is not filled in. + * | +-failureMessage (Required) - The message to display if the field is not filled in. + * | +-noscript (Optional) - will not be checked by javascript + * | + * +-regex (Optional) - Will validate the field using a regular expression. + * | | because of character escaping, you must provide a different expression for the + * | | javascript validation and the server side validation. Both javascript and server side + * | | validation are optional, but if you provide neither, then your field will not be validated. + * | | + * | +-failureMessage (Optional) - The message to display if the regex evaluation returns false. + * | +-jsFailureMessage (Optional) - The message for Javascript to display if regex fails. + * | | If jsFailureMessage is not defined Javascript uses failureMessage. + * | | NOTE: Javascript injects the failure message using createTextNode so &lt; will + * | | be displayed as &lt; + * | | + * | +-pattern (Optional) - The regular expression to test the input at the server side, it's important to use + * | | this if you need to validate the field for security reasons, also it is good because not + * | | all browsers use javascript or have it enabled. + * | | + * | +-jsPattern (Optional) - The regular expression to use for client side, you can use escaped characters to avoid + * | | them being parsed as HTML or javascript. To get javascript to unescape characters use: + * | | {"jsPattern" : "'+unescape('%5E%5B%24')+'"} + * | | NOTE: If no jsPattern is specified, the jsValidator will try to validate + * | | using the server pattern. + * | | + * | +-noscript (Optional) - will not be checked by javascript + * | + * +-mustMatch (Optional) - Will fail if the entry into the field is not the same as the entry in another field. + * | | Good for password confirmation. + * | | + * | +-failureMessage (Required) - The message to display if the field doesn't match the named field. + * | +-name (Required) - The name of the field which this field must match. + * | +-noscript (Optional) - will not be checked by javascript + * | + * +-programmaticValidation (Optional) - This form of validation executes a piece of code which you give it and + * | | if the code returns the word "failed" then it gives the error message. + * | | Remember to put the code in singel quotes ('') because you want the value + * | | of 'code' to equal the literal code, not the output from running it. + * | | + * | +-code (Required) - The code which will be executed to test whether the field is filled in correctly. + * | +-failureMessage (Required) - The message which will be displayed if evaluating the code returns "false" + * | + * +-fieldOkayMessage (Optional) - The message which is displayed by LiveValidation when a field is validated as okay. + * If not specified, will be $defaultFieldOkayMessage + * + * noReturn - If this is specified, the field will not be filled in if there is an error and the user has to fix their + * registration information. If you don't want a password to be passed back in html then set this true + * for the password fields. Used for the captcha because it makes no sense to pass back a captcha answer. + * + * doAfterRegistration - Some Velocity code which will be executed after a successfull registration. + * This is used in the favorite color example. + * Remember to put the code in singel quotes ('') because you want the 'code' entry to equal the literal + * code, not the output from running it. + * + * Each field may not have: (reserved names) + * error - This is used to pass back any error message from the server side code. + * + * NOTE: This template uses a registration method which requires: + * * register_first_name + * * register_last_name + * * xwikiname + * * register_password + * * register2_password + * * register_email + * * template + * Removing or renaming any of these fields will result in undefined behavior. + * + *### +#set($fields = []) +## +## The first name field +#set($field = + {'name' : 'register_first_name', + 'label' : $services.localization.render('core.register.firstName'), + 'params' : { + 'type' : 'text', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + } + } + }) +#set($discard = $fields.add($field)) +## +## The last name field +#set($field = + {'name' : 'register_last_name', + 'label' : $services.localization.render('core.register.lastName'), + 'params' : { + 'type' : 'text', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + } + } + }) +#set($discard = $fields.add($field)) +## +## The user name field, mandatory and programmatically checked to make sure the username doesn't exist. +#set($field = + {'name' : 'xwikiname', + 'label' : $services.localization.render('core.register.username'), + 'params' : { + 'type' : 'text', + 'onfocus' : 'prepareName(document.forms.register);', + 'size' : '60', + 'class' : 'check-unique' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + }, + 'programmaticValidation' : { + 'code' : '#nameAvailable($request.get("xwikiname"))', + 'failureMessage' : $services.localization.render('core.register.userAlreadyExists') + } + } + }) +#set($discard = $fields.add($field)) +## Make sure the chosen user name is not already taken +## This macro is called by programmaticValidation for xwikiname (above) +#macro(nameAvailable, $name) + #if($xwiki.exists("$userSpace$name")) + failed + #end +#end +## +##The password field, mandatory and must be at least 6 characters long. +#set($field = + {'name' : 'register_password', + 'label' : $services.localization.render('core.register.password'), + 'params' : { + 'type' : 'password', + 'autocomplete' : 'off', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + }, + 'regex' : { + 'pattern' : '/.{6,}/', + 'failureMessage' : $services.localization.render('xe.admin.registration.passwordTooShort') + } + } + }) +#set($discard = $fields.add($field)) +## +##The confirm password field, mandatory, must match password field, and must also be 6+ characters long. +#set($field = + {'name' : 'register2_password', + 'label' : $services.localization.render('core.register.passwordRepeat'), + 'params' : { + 'type' : 'password', + 'autocomplete' : 'off', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + }, + 'mustMatch' : { + 'name' : 'register_password', + 'failureMessage' : $services.localization.render('xe.admin.registration.passwordMismatch') + }, + 'regex' : { + 'pattern' : '/.{6,}/', + 'failureMessage' : $services.localization.render('xe.admin.registration.passwordTooShort') + } + } + }) +#set($discard = $fields.add($field)) +## +## The email address field, regex checked with an email pattern. +#set($field = + {'name' : 'register_email', + 'label' : $services.localization.render('core.register.email'), + 'params' : { + 'type' : 'text', + 'size' : '60' + }, + 'validate' : { + 'regex' : { + 'pattern' : '/^([^@\s]+)@((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,})$/', + 'failureMessage' : $services.localization.render('xe.admin.registration.invalidEmail') + }, + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + } + } + }) +#set($discard = $fields.add($field)) +##------------------------------------------------------------- +##Customization +##------------- +#set($field = + {'name' : 'register_affiliation', + 'label' : 'Affiliation', + 'params' : { + 'type' : 'text', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + } + } + }) +#set($discard = $fields.add($field)) +#set($field = + {'name' : 'register_referral', + 'label' : "How did you hear about / Who referred you to PhenomeCentral?", + 'params' : { + 'type' : 'text', + 'size' : '100' + } + }) +#set($discard = $fields.add($field)) +##------------------------------------------------------------ +## +#********* +## Uncomment this code to see an example of how you can easily add a field to the registration page +## NOTE: In order to save the favorite color in the "doAfterRegistration" hook, this page must be +## saved by an administrator and can not self sandboxing. +#set($sandbox = false) +#set($field = + {'name' : 'favorite_color', + 'label' : 'What is your favorite color', + 'params' : { + 'type' : 'text', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.validation.required.message') + }, + 'regex' : { + 'pattern' : '/^green$/', + 'failureMessage' : 'You are not cool enough to register here.' + }, + 'fieldOkayMessage' : 'You are awesome.' + }, + 'doAfterRegistration' : '#saveFavoriteColor()' + }) +#set($discard = $fields.add($field)) +## Save the user's favorite color on their user page. +#macro(saveFavoriteColor) + #set($xwikiname = $request.get('xwikiname')) + #set($userDoc = $xwiki.getDocument("$userSpace$xwikiname")) + $userDoc.setContent("$userDoc.getContent() ${xwikiname}'s favorite color is $request.get('favorite_color')!") + ## The user (who is not yet logged in) can't save documents so saveWithProgrammingRights + ## will save the document as long as the user who last saved this registration page has programming rights. + $userDoc.saveWithProgrammingRights("Saved favorite color from registration form.") +#end +*********### +## +## To disable the captcha on this page, comment out the next two entries. +## The captcha image, not an input field but still defined the same way. +#if($captchaservice + && !$invited + && $xcontext.getUser() == "XWiki.XWikiGuest" + && $requireCaptcha) + ## Empty label field used for padding. + ## Empty 'name' field overriddes name="captcha_image" with "" so name is not specified at all. + #set($field = + {'name' : 'captcha_image', + 'label' : "<span class='hidden'>$services.localization.render('core.captcha.image.label')</span>", + 'tag' : 'img', + 'params' : { + 'src' : $doc.getURL('imagecaptcha'), + 'alt' : $services.localization.render('core.captcha.image.alternateText', [$services.localization.render('core.register.submit')]), + 'name' : '' + } + }) + #set($discard = $fields.add($field)) + ## The captcha field, mandatory, programmatically checked to make sure the captcha is right + ## Not checked by javascript because javascript can't check the captcha and the Ok message because it passes the + ## mandatory test is misleading. + ## and not filled back in if there is an error ('noReturn') + #set($field = + {'name' : 'captcha_answer', + 'label' : $services.localization.render('core.captcha.image.instruction'), + 'params' : { + 'type' : 'text', + 'size' : '60' + }, + 'validate' : { + 'mandatory' : { + 'failureMessage' : $services.localization.render('core.captcha.captchaAnswerIsWrong'), + 'noscript' : true + }, + 'programmaticValidation' : { + 'code' : '#checkCaptcha($request, $request.get("captcha_answer"))', + 'failureMessage' : $services.localization.render('core.captcha.captchaAnswerIsWrong') + } + }, + 'noReturn' : true + }) + #set($discard = $fields.add($field)) +#end +## +## Checks the captcha answer; used by programmaticValidation above. +#macro(checkCaptcha, $request, $answer) + #set($cv = $captchaservice.getCaptchaVerifier('image')) + #if(!$cv.isAnswerCorrect($cv.getUserId($request), $answer)) + failed + #end +#end +## +## Pass the name of the template to $xwiki.createUser so any contained information will be passed in. +#set($field = + {'name' : 'template', + 'params' : { + 'type' : 'hidden', + 'value' : 'XWiki.XWikiUserTemplate' + } + }) +#set($discard = $fields.add($field)) +## +## Pass the redirect parameter on so that the login page may redirect to the right place. +## Not necessary in Firefox 3.0.10 or Opera 9.64, I don't know about IE or Safari. +#set($field = + {'name' : $redirectParam, + 'params' : { + 'type' : 'hidden' + } + }) +#set($discard = $fields.add($field)) +## +####################################################################### +## The Code. +####################################################################### +## +#if($useLiveValidation) + $xwiki.get('jsfx').use('uicomponents/widgets/validation/livevalidation_prototype.js') + $xwiki.get('ssfx').use('uicomponents/widgets/validation/livevalidation.css', true) +#end +## This application's HTML is dynamically generated and editing in WYSIWYG would not work +#if($xcontext.getAction() == 'edit') + $response.sendRedirect("$xwiki.getURL($doc.getFullName(), 'edit')?editor=wiki") +#end +## +## If this document has PR and is not included from another document then it's author should be set to Guest +## for the duration of it's execution in order to improve security. +## Note we compare document ids because +#if($sandbox + && $xcontext.hasProgrammingRights() + && $xcontext.getDoc().getDocumentReference().equals($xwiki.getDocument($documentName).getDocumentReference())) +## + $xcontext.dropPermissions()## +#end +## +## Access level to register must be explicitly checked because it is only checked in XWiki.prepareDocuments +## and this page is accessible through view action. +#if(!$xcontext.hasAccessLevel('register', 'XWiki.XWikiPreferences')) + ## Make an exception if another document with programming permission (Invitation app) has included this + ## document and set $invited to true. + #if(!$invited || !$xcontext.hasProgrammingRights()) + $response.sendRedirect("$xwiki.getURL($doc.getFullName(), 'login')") + #end +#end +## If this is true, then assume the registration page is being viewed inside of a lightbox +#if($request.get('xpage')) + #set($assumeLightbox = true) +#end +## +## Display the heading +##$heading +##--- +##Just need to change the header. No need to create a custom configuration +{{html clean=false wiki=false}} +<style> +.xform .xRequired {float:right;} +.contents input[type="textarea"] {resize:vertical;width: 99%;} +</style> +<span id="request" class="xform"> + <img src="$xwiki.getDocument('ColorThemes.Steel').getAttachmentURL('pc-logo.png')" alt="PhenomeCentral" style="margin-top: -15px; float: right"> + <h2 style="margin-top: 30px;">Request an account</h2> + <div class="clearfloats"></div> + + <div class="contents" style="position:relative; top:5px"> +{{/html}} +##--- +## +## If the submit button has been pressed, then we test the input and maybe create the user. +#if($request.getParameter('xwikiname')) + ## Do server side validation of input fields. + ## This must not be in a #set directive as it will output messages if something goes wrong. + #validateFields($fields, $request) + ##------------------------------------- + #if ("$!{request.confirmation}" == '') + #set ($missingConfirmation = true) + #set ($registrationFailed = true) + #end + ##------------------------------------- + ## If server side validation was successfull, create the user + #if(!$registrationFailed) + #createUser($fields, $request, $response, $doAfterRegistration) + #end +#end +## If the registration was not successful or if the user hasn't submitted the info yet +## Then we display the registration form. +#if(!$registrationDone) + ##Don't need this anymore. + ##$welcomeMessage + + {{html clean=false wiki=false}} + ##---------------------------------- + #if ($missingConfirmation) + #error('PhenomeCentral is targeted to clinicians and scientists working in the rare disorder community. You should not request an account on PhenomeCentral unless you can confirm that you are a doctor, clinical geneticist or scientist working with patients affected by rare disorders.') + #end + ##---------------------------------- + <form id="register" action="" method="post" class="xform"> + <div> + <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" /> + #set ($userDirectoryReference = $services.model.createDocumentReference('', 'Main', 'UserDirectory')) + #if ($xwiki.exists($userDirectoryReference)) + <input type="hidden" name="parent" value="$!{services.model.serialize($userDirectoryReference, 'default')}" /> + #end + #generateHtml($fields, $fieldMandatoryStar, $failureMessageParams) + ## + ##---------------------------------- + <dt> + <label for="comment">Why are you requesting access to PhenomeCentral?</label> + </dt> + <dd> + <textarea id="register_comment" name="register_comment" rows="3" mlb_binding_key="8"></textarea> + </dd> + <dt> + <label for="confirmation"><input id="confirmation" type="checkbox" name="confirmation" style="margin-right: 16px;" mlb_binding_key="9"> + I confirm that I am a doctor, clinical geneticist or scientist working with patients affected by rare disorders. + <span class="xRequired">(Required)</span> + </label> + </dt> + ##----------------------------------- + ## + <div class="wikimodel-emptyline"></div> + <span class="buttonwrapper"> + #if($assumeLightbox) + ## LightBox detected... + <script type="text/javascript"> + ## Make the X button not reload the page. (overriding LbClose) + window.lb.lbClose = function() { + this.lbHide(); + this.lbClearData(); + ##return false; + } + ## Post the form entry to the page and load the result. (we override lbSaveForm) + window.lb.lbSaveForm = function() { + var formParams = Form.serialize(this.form); + Form.disable(this.form); + var ajaxRequest = new Ajax.Request(this.saveUrl, { + parameters: formParams, + asynchronous: false + }); + window.lb.lbFormDataLoaded(ajaxRequest.transport); + } + </script> + ## It doesn't really matter where these are, the scripts will be relocated to the head. + <!-- com.xpn.xwiki.plugin.skinx.CssSkinFileExtensionPlugin --> + <!-- com.xpn.xwiki.plugin.skinx.JsSkinFileExtensionPlugin --> + ## + <input class="button" type="submit" value="$services.localization.render('save')" onclick="window.lb.lbSaveForm();"/> + </span>#* End ButtonWrapper then start another...*#<span class="buttonwrapper"> + <input class="button secondary" type="submit" value="$services.localization.render("cancel")" onclick="Form.disable(window.lb.form); window.lb.lbClose();"/> + #else + ## Not using the LightBox + <input type="submit" value="$services.localization.render('core.register.submit')" class="button"/> + #end + </span>## ButtonWrapper + </div> + </form> + #if($useLiveValidation) + #generateJavascript($fields) + #end + {{/html}} + + ## + ## Allow permitted users to configure this application. + #if($xcontext.getUser() != 'XWiki.XWikiGuest' && $xcontext.hasAccessLevel("edit", $documentName)) + [[{{translation key="xe.admin.registration.youCanConfigureRegistrationHere"/}}>>XWiki.XWikiPreferences?section=Registration&editor=globaladmin#HCustomizeXWikiRegistration]] + {{html}}<a href="$xwiki.getURL($documentName, 'edit', 'editor=wiki')">$services.localization.render('xe.admin.registration.youCanConfigureRegistrationFieldsHere')</a>{{/html}} + #end +## If the registration is done (successful) and we detect the Lightbox simply send the user back to the original page. +#elseif($assumeLightbox) + {{html clean=false wiki=false}} + <script type="text/javascript"> + var url = window.lb.redirectUrl; + window.lb.lbClose; + if (url != undefined) { + if(window.location.pathname + window.location.search == url) { + ## Under certain circumstances (bug) Opera will not load a page if the location is the same as the current page. + ## In these cases, location.reload() doesn't work either, the only solution (I could find) was to change the URL. + window.location.href = url + "&"; + } else { + window.location.href = url; + } + } + </script> + </div> +</span> +{{/html}} +#end +## +####### The Macros (nothing below this point is run directly) ######### +#* + * Server side validation, this is necessary for security and because not everyone has Javascript + * + * @param $fields The array of fields to validate. + * @param $request An XWikiRequest object which made the register request, used to get parameters. + *### +#macro(validateFields, $fields, $request) + #foreach($field in $fields) + #if($field.get('validate') && $field.get('name')) + #set($fieldName = $field.get('name')) + #set($validate = $field.get('validate')) + #set($error = '') + #set($value = $request.get($fieldName)) + #if($value && $value != '') + ## + ## mustMatch validation + #if($error == '' && $validate.get('mustMatch')) + #set($mustMatch = $validate.get('mustMatch')) + #if($mustMatch.get('name') && $mustMatch.get('failureMessage')) + #if($request.get($fieldName) != $request.get($mustMatch.get('name'))) + #set($error = $mustMatch.get('failureMessage')) + #end + #else + ERROR: In field: ${fieldName}: mustMatch validation required both name + (of field which this field must match) and failureMessage. + #end + #end + ## + ## Regex validation + ## We won't bother with regex validation if there is no entry, that would defeat the purpose of 'mandatory' + #if($error == '' && $validate.get('regex') && $value && $value != '') + #set($regex = $validate.get('regex')) + #if($regex.get('pattern') && $regex.get('failureMessage')) + ## Make Java regexes more compatible with Perl/js style regexes by removing leading and trailing / + #if($regex.get('pattern').length() > 1) + #set($pattern = $regex.get('pattern')) + #if($pattern.lastIndexOf('/') < $pattern.length() - 1) + ERROR: In field: ${fieldName}: regex validation does not allow flags after the /, please fix [${pattern}]. + #end + #set($pattern = $pattern.substring($mathtool.add(1, $pattern.indexOf('/')), $pattern.lastIndexOf('/'))) + #else + ## I don't expect this but want to maintain compatibility. + #set($pattern = $regex.get('pattern')) + #end + #if($regextool.find($value, $pattern).isEmpty()) + #set($error = $regex.get('failureMessage')) + #end + #elseif($regex.get('pattern')) + ERROR: In field: ${fieldName}: regex validation must include failureMessage. + #end + #end + ## + ## If regex and mustMatch validation passed, try programmatic validation + #if($error == '' && $validate.get('programmaticValidation')) + #set($pv = $validate.get('programmaticValidation')) + #if($pv.get('code') && $pv.get('failureMessage')) + #set($pvReturn = "#evaluate($pv.get('code'))") + #if($pvReturn.indexOf('failed') != -1) + #set($error = $pv.get('failureMessage')) + #end + #else + ERROR: In field: ${fieldName}: programmaticValidation requires code and failureMessage + #end + #end + #else + ## + ## If no content, check if content is mandatory + #if($validate.get('mandatory')) + #set($mandatory = $validate.get('mandatory')) + #if($mandatory.get('failureMessage')) + #set($error = $mandatory.get('failureMessage')) + #else + ERROR: In field: ${fieldName}: mandatory validation requires a failureMessage + #end + #end + #end + #if($error != '') + #set($discard = $field.put('error', $error)) + #set($registrationFailed = true) + #end + #elseif(!$field.get('name')) + ERROR: Field with no name. + #end##if(validate) + #end##loop +#end##macro +#* + * Create the user. + * Calls $xwiki.createUser to create a new user. + * + * @param $request An XWikiRequest object which made the register request. + * @param $response The XWikiResponse object to send any redirects to. + * @param $doAfterRegistration code block to run after registration completes successfully. + *### +#macro(createUser, $fields, $request, $response, $doAfterRegistration) + ## CSRF check + #if(${services.csrf.isTokenValid("$!{request.getParameter('form_token')}")}) + ## See if email verification is required and register the user. + #if($xwiki.getXWikiPreferenceAsInt('use_email_verification', 0) == 1) + #set($reg = $xwiki.createUser(true)) + #else + #set($reg = $xwiki.createUser(false)) + #end + #else + $response.sendRedirect("$!{services.csrf.getResubmissionURL()}") + #end + ## + ## Handle output from the registration. + #if($reg && $reg <= 0) + {{error}} + #if($reg == -2) + {{translation key="core.register.passwordMismatch"/}} + ## -3 means username taken, -8 means username is superadmin name + #elseif($reg == -3 || $reg == -8) + {{translation key="core.register.userAlreadyExists"/}} + #elseif($reg == -4) + {{translation key="core.register.invalidUsername"/}} + #else + {{translation key="core.register.registerFailed" parameters="$reg"/}} + #end + {{/error}} + #elseif($reg) + ## Registration was successful + #set($registrationDone = true) + ## + ## If there is any thing to "doAfterRegistration" then do it. + #foreach($field in $fields) + #if($field.get('doAfterRegistration')) + #evaluate($field.get('doAfterRegistration')) + #end + #end + ## If there is a "global" doAfterRegistration, do that as well. + #if($doAfterRegistration) + #set($discard = $doAfterRegistration.toString()) + #end + ## Define some strings which may be used by autoLogin or loginButton + #set($userName = $!request.get('xwikiname')) + #set($password = $!request.get('register_password')) + #set($loginURL = $xwiki.getURL($loginPage, $loginAction)) + #if("$!request.getParameter($redirectParam)" != '') + #set($redirect = $request.getParameter($redirectParam)) + #else + #set($redirect = $defaultRedirect) + #end + ## Display a "registration successful" message + ##evaluate($registrationSuccessMessage) ##COMMENTED OUT + ## Empty line prevents message from being forced into a <p> block. + + ## Give the user a login button which posts their username and password to loginsubmit + ##======================================== + ##The original HTML was completely deleted + ##======================================== + #if($loginButton) + {{html clean=false wiki=false}} + #info('Thank you for your interest in PhenomeCentral. We took note of your request and we will process it shortly.') + {{/html}} + #end + #end + ## +#end## createUser Macro +#* + * Generate HTML form, this is the only place where HTML is written. + * + * @param $fields The array of fields to use for generating html code. + * @param $fieldMandatoryStar The tag parameters for a * indicating a mandatory field. + * @param $failureMessageParams The tag parameters for a failure message. + *### +#macro(generateHtml, $fields, $fieldMandatoryStar, $failureMessageParams) + ## Put the same values back into the fields. + #getParams($fields) + ## + <dl> + #foreach($field in $fields) + #if($field.get('name')) + #set($fieldName = $field.get('name')) + #if($field.get('label')) + #set($label = $field.get('label')) + <dt><label for="$fieldName">$label + #if($field.get('validate').get('mandatory')) + <span ## + #foreach($entry in $fieldMandatoryStar.entrySet()) + $entry.getKey()="$entry.getValue()" ## + #end + >$services.localization.render('core.validation.required')</span> + #end + </label> + </dt> + #end + ## If no tag then default tag is <input> + #if($field.get('tag')) + #set($tag = $field.get('tag')) + #else + #set($tag = 'input') + #end + <dd><$tag id="$fieldName" ## + #set($params = $field.get('params')) + ## If no name parameter is spacified, then we use the field name + #if(!$params.get('name')) + #set($discard = $params.put('name', $fieldName)) + #end + #foreach($entry in $params.entrySet()) + ## If a parameter is specified as '' then we don't include it. + #if($entry.getValue() != '') + $entry.getKey()="$escapetool.xml($entry.getValue())" ## + #end + #end + ></$tag> + #if($field.get('error')) + <span ## + #foreach($entry in $failureMessageParams.entrySet()) + $entry.getKey()="$entry.getValue()" ## + #end + >$field.get('error')</span> + #end + </dd> + #else + ERROR: Field with no name. + #end##if fieldName exists + #end + </dl> +#end +#* + * Generate the Javascript for interacting with LiveValidation. + * + * @param $fields The array of fields which to validate. + *### +#macro(generateJavascript, $fields) + <script type='text/javascript'> + /* <![CDATA[ */ + document.observe('xwiki:dom:loaded', function() { + ## + #foreach($field in $fields) + #if($field.get('validate') && $field.get('name')) + #set($validate = $field.get('validate')) + #if(($validate.get('mandatory') && !$validate.get('mandatory').get('noscript')) + || ($validate.get('regex') && !$validate.get('regex').get('noscript')) + || ($validate.get('mustMatch') && !$validate.get('mustMatch').get('noscript'))) + #set($fieldName = $field.get('name')) + #if($validate.get('fieldOkayMessage')) + #set($okayMessage = $validate.get('fieldOkayMessage')) + #else + #set($okayMessage = $defaultFieldOkayMessage) + #end + var ${fieldName}Validator = new LiveValidation("$fieldName", { validMessage: "$okayMessage", wait: 500} ); + ## + #if($validate.get('mandatory')) + #set($mandatory = $validate.get('mandatory')) + #if($mandatory.get('failureMessage') && !$mandatory.get('noscript')) + ${fieldName}Validator.add( Validate.Presence, { failureMessage: "$!mandatory.get('failureMessage')"} ); + #end + #end + ## + #if($validate.get('mustMatch')) + #set($mustMatch = $validate.get('mustMatch')) + #if($mustMatch.get('name') && $mustMatch.get('failureMessage') && !$mustMatch.get('noscript')) + ${fieldName}Validator.add( Validate.Confirmation, { match: $$("input[name=$!mustMatch.get('name')]")[0], failureMessage: "$!mustMatch.get('failureMessage')"} ); + #end + #end + ## + #if($validate.get('regex')) + #set($regex = $validate.get('regex')) + #set($pattern = "") + #if($regex.get('jsPattern')) + #set($pattern = $regex.get('jsPattern')) + #elseif($regex.get('pattern')) + #set($pattern = $regex.get('pattern')) + #end + #set($failMessage = "") + #if($regex.get('jsFailureMessage')) + #set($failMessage = $regex.get('jsFailureMessage')) + #elseif($regex.get('failureMessage')) + #set($failMessage = $regex.get('failureMessage')) + #end + #if($pattern != '' && $failMessage != '' && !$regex.get('noscript')) + ${fieldName}Validator.add( Validate.Format, { pattern: $pattern, failureMessage: "$failMessage"} ); + #end + #end##if regex + #end##if contains js validateable fields. + #end##if validate + #end##loop + });// ]]> + </script> +#end##macro +#* + * Get parameters from request so that values will be filled in if there is a mistake + * in one of the entries. Entries will be returned to fields[n].params.value + * Fields will not be returned if they have either noReturn or error specified. + * + * @param $fields The array of fields to get parameters for. + *### +#macro(getParams $fields) + #foreach($field in $fields) + #if($field.get('name') && $request.get($field.get('name'))) + #if(!$field.get('noReturn') && !$field.get('error')) + #if(!$field.get('params')) + #set($params = {}) + #set($discard = $field.put('params', $params)) + #else + #set($params = $field.get('params')) + #end + #set($discard = $params.put('value', $request.get($field.get('name')))) + #end + #end + #end +#end +#* + * Get the configuration from the configuration object. + * + * @param $configDocumentName The name of the document to get the configuration from. + *### +#macro(loadConfig, $configDocumentName) + #set($configDocument = $xwiki.getDocument($configDocumentName)) + #if(!$configDocument || !$configDocument.getObject($documentName)) + ## No config document, load defaults. + #set($heading = "$services.localization.render('core.register.title')") + #set($welcomeMessage = "$services.localization.render('core.register.welcome')") + #set($useLiveValidation = true) + #set($defaultFieldOkayMessage = "$services.localization.render('core.validation.valid.message')") + #set($loginButton = true) + #set($defaultRedirect = "$xwiki.getURL($services.model.resolveDocument('', 'default', $doc.documentReference.extractReference('WIKI')))") + #set($userFullName = "$request.get('register_first_name') $request.get('register_last_name')") + #set($registrationSuccessMessage = '{{info}}$services.localization.render("core.register.successful", ["[[${userFullName}>>${userSpace}${userName}]]", ${userName}]){{/info}}') + #else + #set($configObject = $configDocument.getObject($documentName)) + #if ($xcontext.action == 'register') + #set ($heading = "(% id='document-title'%)((( = #evaluate($configObject.getProperty('heading').getValue()) = )))(%%)") + #else + #set ($heading = "= #evaluate($configObject.getProperty('heading').getValue()) =") + #end + #set($welcomeMessage = "#evaluate($configObject.getProperty('welcomeMessage').getValue())") + #if($configObject.getProperty('liveValidation_enabled').getValue() == 1) + #set($useLiveValidation = true) + #end + #set($defaultFieldOkayMessage = "#evaluate($configObject.getProperty('liveValidation_defaultFieldOkMessage').getValue())") + #if($configObject.getProperty('loginButton_enabled').getValue() == 1) + #set($loginButton = true) + #end + #if($configObject.getProperty('loginButton_autoLogin_enabled').getValue() == 1) + #set($autoLogin = true) + #end + #set($defaultRedirect = "#evaluate($configObject.getProperty('defaultRedirect').getValue())") + #set($registrationSuccessMessage = "$configObject.getProperty('registrationSuccessMessage').getValue()") + #if($configObject.getProperty('requireCaptcha').getValue() == 1) + #set($requireCaptcha = true) + #end + #end +#end +{{/velocity}} + diff --git a/ui/src/main/resources/PhenomeCentral/UsernameValidation.xml b/ui/src/main/resources/PhenomeCentral/UsernameValidation.xml new file mode 100644 index 00000000..3fd866da --- /dev/null +++ b/ui/src/main/resources/PhenomeCentral/UsernameValidation.xml @@ -0,0 +1,137 @@ + + + + + + PhenomeCentral + UsernameValidation + + + 0 + PhenomeCentral.register + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1394037343000 + 1394053321000 + 1394053266000 + 1.1 + UsernameValidation + + + + false + xwiki/2.1 + false + + + XWiki.XWikiRights + + + + + + + + + 1 + 0 + select + allow + allow + 4 + Allow/Deny + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + 0 + input + 1 + groups + 1 + 1 + Groups + 0 + + 5 + 0 + com.xpn.xwiki.objects.classes.GroupsClass + + + 0 + 0 + select + 1 + levels + 2 + Levels + 0 + + 3 + 0 + com.xpn.xwiki.objects.classes.LevelsClass + + + 0 + 0 + input + 1 + users + 3 + 1 + Users + 0 + + 5 + 0 + com.xpn.xwiki.objects.classes.UsersClass + + + PhenomeCentral.UsernameValidation + 0 + XWiki.XWikiRights + afed51bc-c308-4b69-9361-fdabb4ce55bd + + 1 + + + xwiki:XWiki.XWikiAllGroup, + + + view + + + XWikiGuest.XWikiGuest + + + +{{velocity}} +#if ($xwiki.getDocumentAsAuthor("xwiki:XWiki.$!{request.eid}").isNew()) + $response.setStatus(404) +#else + $response.setStatus(409) +#end +{{/velocity}} + + diff --git a/ui/src/main/resources/XWiki/AdminPendingUsersData.xml b/ui/src/main/resources/XWiki/AdminPendingUsersData.xml new file mode 100644 index 00000000..3d04d126 --- /dev/null +++ b/ui/src/main/resources/XWiki/AdminPendingUsersData.xml @@ -0,0 +1,151 @@ + + + + + + XWiki + AdminPendingUsersData + + + 0 + XWiki.AdminSheet + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1393628431000 + 1393883371000 + 1393883371000 + 1.1 + AdminPendingUsersData + + + + false + xwiki/2.0 + true + {{velocity}} +$response.setContentType("application/x-json") +##$response.setContentType("text") +#set ($offset = $mathtool.toInteger($request.get('offset'))) +## offset starts from 0 in velocity and 1 in javascript +#set ($off = $offset - 1) +#set ($limit = $mathtool.toInteger($request.get('limit'))) + +#set( $rm = $xwiki.rightsmanager.usersApi ) + +#### get all the request parameters which are filters +#set( $params = $request.getParameterMap() ) +#set( $keys = $params.keySet() ) +#set( $defaultKeys = ["xpage", "offset", "limit", "wiki", "reqNo", "sort", "dir", 'outputSyntax'] ) +#set( $docProps = ["fullName", "name"] ) +#set ($filterMap = {}) +#set ($orderList = []) + +#foreach( $key in $keys ) + #if(! $defaultKeys.contains( $key ) ) + ## build the filters map + #foreach( $i in $params.get( $key ) ) #set( $value = $i ) #end + #if( $docProps.contains( $key )) + #set ($arr = []) + #set( $discard = $arr.add( null ) ) ## this may be variable... + #set( $discard = $arr.add( "$value" ) ) + #set( $discard = $filterMap.put("$key", $arr)) + #set( $discard = $orderList.add( "$key" )) + #else + #set ($arr = []) + #set( $discard = $arr.add( "StringProperty" ) ) ## this may be variable... + #set( $discard = $arr.add( "$value" ) ) + #set( $discard = $filterMap.put("$key", $arr )) + #set ($arr2 = []) + #set( $discard = $arr2.add( "$key" ) ) + #set( $discard = $arr2.add( "StringProperty" ) ) + #set( $discard = $orderList.add( $arr2 )) + #end + #end +#end + +#if($orderList.size() == 0) +#set($disc = $orderList.add("name")) ## initially fiter by "name" !!! +#end + + +#foreach( $i in $params.get( "wiki" ) ) #set( $value = $i ) #end +#if( $value == "local" ) + #set( $users = $rm.getAllMatchedLocalUsers( $filterMap, $limit, $off, $orderList ) ) + #set( $countUsers = $rm.countAllMatchedLocalUsers( $filterMap ) ) +#elseif( $value == "global" ) + #set( $users = $rm.getAllMatchedGlobalUsers( $filterMap, $limit, $off, $orderList ) ) + #set( $countUsers = $rm.countAllMatchedGlobalUsers( $filterMap ) ) +#else + ## get both local and global users + #set( $users = $rm.getAllMatchedUsers( $filterMap, $limit, $off, $orderList ) ) + #set( $countUsers = $rm.countAllMatchedUsers( $filterMap ) ) +#end + +## ================ +## Custom modifications. Loop over default results and check if active. Put into a new list. +## Makes no modifications to old code, however, it changes some values before it is passed to JSON generation. +## Worst choice from the perspective of performance. +## ================ +#set ($nonActiveUsers = []) +#set ($countUsers = 0) +#foreach ($user in $users) + #set ($active = $user.getObject('XWiki.XWikiUsers').getProperty('active').getValue()) + #if ($active == 0) + #set ($suppress = $nonActiveUsers.add($user)) + #set ($countUsers = $countUsers + 1) + #end +#end +## json starts +{ +"totalrows": $countUsers, +"returnedrows": #if($countUsers < $limit) $countUsers #else $limit #end, +"offset": $offset, +"reqNo": $mathtool.toInteger($request.reqNo), +"rows": [ +#foreach( $user in $nonActiveUsers ) + #if($xcontext.user == $user.fullName) + #set($grayed = true) + #else + #set($grayed = false) + #end + #set($wikiname = $user.getWiki()) + #if($wikiname != "xwiki" || $wikiname == $xcontext.database) #set($wikiname = "local") #end + #if( $velocityCount > 1 ) , #end + {"username" : "$!{escapetool.javascript($user.name)}", + "fullname" : "$!{escapetool.javascript($user.fullName)}", + "wikiname" : "$!{escapetool.javascript($wikiname)}", + + "firstname" : "$!{escapetool.javascript($user.getObject('XWiki.XWikiUsers').getProperty('first_name').getValue())}", + "lastname" : "$!{escapetool.javascript($user.getObject('XWiki.XWikiUsers').getProperty('last_name').getValue())}", + "userurl" : "$xwiki.getURL($user.fullName)", + "usersaveurl" : "$user.getURL("save")", + "userinlineurl" : "$user.getURL("edit", "xpage=edituser")", + "docurl" : "$xwiki.getURL("XWiki.XWikiPreferences", "admin", "section=PendingUsers")", + "grayed" : "$grayed" + } +#end +]} + +### end of json +{{/velocity}} + diff --git a/ui/src/main/resources/XWiki/AdminPendingUsersSheet.xml b/ui/src/main/resources/XWiki/AdminPendingUsersSheet.xml new file mode 100644 index 00000000..e3496a4c --- /dev/null +++ b/ui/src/main/resources/XWiki/AdminPendingUsersSheet.xml @@ -0,0 +1,363 @@ + + + + + + XWiki + AdminPendingUsersSheet + + + 0 + XWiki.AdminSheet + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1393614771000 + 1393882905000 + 1393882465000 + 1.1 + AdminPendingUsersSheet + + + + false + xwiki/2.0 + true + + + XWiki.ConfigurableClass + + + + + + + + + + + 0 + select + + advancedOnly + 5 + advancedOnly + 0 + + + com.xpn.xwiki.objects.classes.BooleanClass + + + + 0 + categoryPriority + 2 + integer + categoryPriority + 30 + 0 + + + com.xpn.xwiki.objects.classes.NumberClass + + + + 0 + --- + codeToExecute + 11 + 0 + codeToExecute + 5 + 40 + 0 + + + com.xpn.xwiki.objects.classes.TextAreaClass + + + + 0 + configurationClass + 7 + 0 + configurationClass + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + + + 0 + checkbox + + configureGlobally + 8 + configureGlobally + 0 + + + com.xpn.xwiki.objects.classes.BooleanClass + + + + 0 + displayInCategory + 1 + 0 + displayInCategory + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + + 0 + displayInSection + 3 + 0 + displayInSection + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + + 0 + heading + 6 + 0 + heading + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + + 0 + iconAttachment + 12 + 0 + iconAttachment + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + + 0 + linkPrefix + 9 + 0 + linkPrefix + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + 0 + + 0 + input + 1 + propertiesToShow + 10 + 0 + propertiesToShow + 1 + + ,| + 20 + none + 0 + + + + com.xpn.xwiki.objects.classes.StaticListClass + + + + 0 + sectionPriority + 4 + integer + sectionPriority + 30 + 0 + + + com.xpn.xwiki.objects.classes.NumberClass + + + XWiki.AdminPendingUsersSheet + 0 + XWiki.ConfigurableClass + 6f3d7fe3-9508-4eb3-945e-5cbed148f7ad + + 0 + + + + + + + + + + + + 1 + + + usersgroups + + + PendingUsers + + + + + + + + + + + + + + + + + + {{velocity}} +### Globally administrate the users in a wiki. +#set($formname = "update") +#set($saveaction = "save") +## +## inject needed JS and CSS files +## +#set($ok = $xwiki.jsfx.use("js/xwiki/lightbox/lightbox.js", true)) +#set($ok = $xwiki.ssfx.use("js/xwiki/lightbox/lightbox.css", true)) +#set($ok = $xwiki.jsfx.use("js/xwiki/usersandgroups/nonactiveusers.js", true)) +#set($ok = $xwiki.ssfx.use("js/xwiki/usersandgroups/usersandgroups.css", true)) +#set($ok = $xwiki.jsfx.use("js/xwiki/table/livetable.js", true)) +#set($ok = $xwiki.ssfx.use("js/xwiki/table/livetable.css", true)) +#set($ok = $xwiki.ssx.use("XWiki.XWikiUserSheet")) +#set($ok = $xwiki.jsx.use("XWiki.XWikiUserSheet")) +## +## url to get the users for displaying them in the ajax-based table +## +#set($url = $xwiki.getURL('XWiki.AdminPendingUsersData', 'get', 'outputSyntax=plain')) +#if($xcontext.database != "xwiki") + #set($mainwk = false) +#else + #set($mainwk = true) +#end +{{html}} +<div id="xwikieditcontent"> + <table id="userstable" class="xwiki-livetable"> + <tr> + <td class="xwiki-livetable-pagination" colspan="2"> + <span id="userstable-limits" class="xwiki-livetable-limits"></span> + <span id="userstable-ajax-loader" class="xwiki-livetable-loader"><img src="$xwiki.getSkinFile('icons/xwiki/ajax-loader-large.gif')" alt="$services.localization.render('platform.livetable.loading')" title="" />$services.localization.render('platform.livetable.loading')</span> + <span class="pagination"> + <span id="userstable-pagination-text" class="xwiki-livetable-pagination-text">$services.localization.render('platform.livetable.paginationPage')</span> + <span id="userstable-pagination" class="xwiki-livetable-pagination-content" ></span> + </span> + </td> + </tr> + <tr> + <td class="xwiki-livetable-display-container"> + <table class="xwiki-livetable-display"> + <thead class="xwiki-livetable-display-header"> + <tr> + <th class="xwiki-livetable-display-header-text" scope="col">$services.localization.render('xe.admin.users.username')</th> + <th class="xwiki-livetable-display-header-text" scope="col">$services.localization.render('xe.admin.users.firstname')</th> + <th class="xwiki-livetable-display-header-text" scope="col">$services.localization.render('xe.admin.users.lastname')</th> + <th class="xwiki-livetable-display-header-text" scope="col">$services.localization.render('xe.admin.users.manage')</th> + </tr> + <tr id="userstable-filters" class="xwiki-livetable-display-filters"> + <td class="xwiki-livetable-display-header-filter"><label for="name" class="hidden">$services.localization.render('xe.admin.users.filter.username')</label><input id="name" name="name" type="text" class="filter"/></td> + <td class="xwiki-livetable-display-header-filter"><label for="first_name" class="hidden">$services.localization.render('xe.admin.users.filter.username')</label><input id="first_name" name="first_name" type="text" class="filter"/></td> + <td class="xwiki-livetable-display-header-filter"><label for="last_name" class="hidden">$services.localization.render('xe.admin.users.filter.username')</label><input id="last_name" name="last_name" type="text" class="filter"/></td> + <td class="xwiki-livetable-display-header-filter"> + #if(!$mainwk) + <select name="wiki" class="filter"> + <option value="local" selected="selected">$services.localization.render('rightsmanager.local')</option> + <option value="global">$services.localization.render('rightsmanager.global')</option> + <option value="both">$services.localization.render('rightsmanager.both')</option> + </select> + #else + <input name="wiki" type="hidden" value="local" /> + #end + </td> + </tr> + </thead> + <tbody id="userstable-display" class="xwiki-livetable-display-body"> + <tr> + <td colspan="4">&nbsp;</td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr><td colspan="3" id="tdAddNewUserOrGroup"> + <span class="buttonwrapper"><a href="#" id="addNewUser" class="addNewUserOrGroup">$services.localization.render('rightsmanager.addnewuser')</a></span> + </td></tr> + </table> + <script type="text/javascript"> + // <![CDATA[ + (function() { + var startup = function() { + var callback = function(row, i, table) { return displayUsers(row, i, table, "$!{services.csrf.getToken()}"); }; + var ta = new XWiki.widgets.LiveTable("$url", "userstable", callback); + #set($registerurl = $doc.getURL('view', 'xpage=registerinline')) + #set($saveurl = $doc.getURL('register', 'xpage=registerinline')) + #set($redirectuserurl = $xwiki.getDocument('XWiki.XWikiPreferences').getURL('admin', "editor=${editor}&section=Users")) + Event.observe($('addNewUser'), "click", makeAddHandler("$registerurl", "$saveurl", "$redirectuserurl")); + } + if ((typeof(XWiki) != 'undefined') && (typeof(XWiki.widgets) != 'undefined') && (typeof(XWiki.widgets.LiveTable) != 'undefined')) { + startup(); + } else { + document.observe('xwiki:livetable:loading', startup); + } + })(); + // ]]> + </script> +</div> ## end of xwikieditcontent +{{/html}} +{{/velocity}} + diff --git a/ui/src/main/resources/XWiki/ManualAccountValidation.xml b/ui/src/main/resources/XWiki/ManualAccountValidation.xml new file mode 100644 index 00000000..c5fe1fb1 --- /dev/null +++ b/ui/src/main/resources/XWiki/ManualAccountValidation.xml @@ -0,0 +1,147 @@ + + + + + + XWiki + ManualAccountValidation + + + 0 + XWiki.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1393874349000 + 1393887447000 + 1393887447000 + 1.1 + + <defaultTemplate/> + <validationScript/> + <comment/> + <minorEdit>false</minorEdit> + <syntaxId>xwiki/2.0</syntaxId> + <hidden>true</hidden> + <object> + <class> + <name>XWiki.Mail</name> + <customClass/> + <customMapping/> + <defaultViewSheet/> + <defaultEditSheet/> + <defaultWeb/> + <nameField/> + <validationScript/> + <html> + <disabled>0</disabled> + <name>html</name> + <number>4</number> + <prettyName>HTML</prettyName> + <rows>15</rows> + <size>80</size> + <unmodifiable>0</unmodifiable> + <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType> + </html> + <language> + <disabled>0</disabled> + <name>language</name> + <number>2</number> + <prettyName>Language</prettyName> + <size>5</size> + <unmodifiable>0</unmodifiable> + <classType>com.xpn.xwiki.objects.classes.StringClass</classType> + </language> + <subject> + <disabled>0</disabled> + <name>subject</name> + <number>1</number> + <prettyName>Subject</prettyName> + <size>40</size> + <unmodifiable>0</unmodifiable> + <classType>com.xpn.xwiki.objects.classes.StringClass</classType> + </subject> + <text> + <disabled>0</disabled> + <name>text</name> + <number>3</number> + <prettyName>Text</prettyName> + <rows>15</rows> + <size>80</size> + <unmodifiable>0</unmodifiable> + <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType> + </text> + </class> + <name>XWiki.ManualAccountValidation</name> + <number>0</number> + <className>XWiki.Mail</className> + <guid>bf97bf71-ec20-42b0-8577-21068d41d00c</guid> + <property> + <html><p>Hello,</p> +<p>Your account ${userName} has been activated.</p> +<p>You can now log in at <a href="${loginURL}">${platformName}</a>.</p> + +<p>Best wishes,<br> +The ${platformName} team</p></html> + </property> + <property> + <language/> + </property> + <property> + <subject>You account at PhenomeCentral has been approved</subject> + </property> + <property> + <text>Hello, +Your account ${userName} has been activated. +You can now log in at ${loginURL}. + +Best wishes, +The ${platformName} team</text> + </property> + </object> + <content>{{velocity}} +$response.setContentType("application/x-json") +#if("$!{request.xwikiname}" != '') + #set ($userDoc = $xwiki.getDocument(${request.xwikiname})) + #set ($user = $userDoc.getObject("XWiki.XWikiUsers")) + $user.set('active', 1) + #set ($email = $user.getProperty('email').getValue()) + + #if ($!{email} != "") + ##set ($userName = ) + #set ($emailStatus = $xwiki.mailsender.sendMessageFromTemplate("PhenomeCentral <noreply@phenomecentral.org>", "$email", $xwiki.null, $xwiki.null, "", "XWiki.ManualAccountValidation", + {"userName": $xwiki.getDocument($request.xwikiname).name, + "platformName": "PhenomeCentral", + "loginURL": $xwiki.getDocument($services.model.resolveDocument('', 'default', $doc.documentReference.extractReference('WIKI'))).getExternalURL()})) + #else + #set ($emailStatus = 0) + #end + #if ($emailStatus == 0) + $userDoc.save() +true + #else +false + #end +#end +{{/velocity}} +</content> +</xwikidoc> diff --git a/ui/src/main/resources/XWiki/UserInactive.xml b/ui/src/main/resources/XWiki/UserInactive.xml new file mode 100644 index 00000000..e5f80ba0 --- /dev/null +++ b/ui/src/main/resources/XWiki/UserInactive.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. +--> + +<xwikidoc> + <web>XWiki</web> + <name>UserInactive</name> + <language/> + <defaultLanguage/> + <translation>0</translation> + <parent>XWiki.WebHome</parent> + <creator>xwiki:XWiki.Admin</creator> + <author>xwiki:XWiki.Admin</author> + <customClass/> + <contentAuthor>xwiki:XWiki.Admin</contentAuthor> + <creationDate>1393884274000</creationDate> + <date>1393884375000</date> + <contentUpdateDate>1393884375000</contentUpdateDate> + <version>1.1</version> + <title/> + <defaultTemplate/> + <validationScript/> + <comment/> + <minorEdit>false</minorEdit> + <syntaxId>xwiki/2.1</syntaxId> + <hidden>false</hidden> + <content>{{info}}Please wait for your account to be approved. Thank you.{{/info}}</content> +</xwikidoc> diff --git a/ui/src/main/resources/XWiki/XWikiPreferences.xml b/ui/src/main/resources/XWiki/XWikiPreferences.xml index 11e31106..f83bcd44 100644 --- a/ui/src/main/resources/XWiki/XWikiPreferences.xml +++ b/ui/src/main/resources/XWiki/XWikiPreferences.xml @@ -1436,7 +1436,7 @@ </users> </class> <property> - <allow>0</allow> + <allow>1</allow> </property> <property> <levels>register</levels> @@ -2583,6 +2583,9 @@ <property> <admin_email/> </property> + <property> + <auth_active_check>1</auth_active_check> + </property> <property> <authenticate_edit>0</authenticate_edit> </property> @@ -2731,18 +2734,23 @@ $xwiki.ssx.use($xwiki.getSpacePreference('colorTheme'))</meta> <property> <upload_maxsize>1073741824</upload_maxsize> </property> + <property> + <use_email_verification>1</use_email_verification> + </property> <property> <validation_email_content>#set ($wikiname = $request.serverName) #set ($host = ${request.getRequestURL()}) #set ($host = ${host.substring(0, ${host.indexOf('/', ${mathtool.add(${host.indexOf('//')}, 2)})})}) -Subject: Validate your account on ${wikiname} +Subject: Your account request on ${wikiname} Hello ${xwiki.getUserName("XWiki.$xwikiname", false)}, -This email address was used to register a new account on ${wikiname}. If you did not make the request, please ignore this message. +Thank you for registering on ${wikiname}. We have received your request and we will review it shortly. +You will receive an account activation email once your request is approved. -In order to activate your account, please follow this link: -${host}${xwiki.getURL('XWiki.AccountValidation', 'view', "validkey=${validkey}&xwikiname=${xwikiname}")}</validation_email_content> +Best wishes, +The ${wikiname} Team +##${host}${xwiki.getURL('XWiki.AccountValidation', 'view', "validkey=${validkey}&xwikiname=${xwikiname}")}</validation_email_content> </property> <property> <version><a href="http://phenotips.org">PhenoTips</a> version $!{services.distribution.distributionExtension.id.version}</version> diff --git a/ui/src/main/resources/XWiki/XWikiUsers.xml b/ui/src/main/resources/XWiki/XWikiUsers.xml new file mode 100644 index 00000000..9b8ab185 --- /dev/null +++ b/ui/src/main/resources/XWiki/XWikiUsers.xml @@ -0,0 +1,382 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. +--> + +<xwikidoc> + <web>XWiki</web> + <name>XWikiUsers</name> + <language/> + <defaultLanguage/> + <translation>0</translation> + <parent>XWiki.XWikiClasses</parent> + <creator>xwiki:XWiki.Admin</creator> + <author>xwiki:XWiki.Admin</author> + <customClass/> + <contentAuthor>xwiki:XWiki.Admin</contentAuthor> + <creationDate>1394145486000</creationDate> + <date>1394149023000</date> + <contentUpdateDate>1394149023000</contentUpdateDate> + <version>1.1</version> + <title>XWiki User Class + + + + false + xwiki/2.1 + true + + XWiki.XWikiUsers + + + + + + + + + 0 + select + yesno + accessibility + 16 + Enable extra accessibility features + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + select + active + active + 6 + Active + 0 + com.xpn.xwiki.objects.classes.BooleanClass + +
+ 0 + address + 22 + Address + 3 + 40 + 0 + com.xpn.xwiki.objects.classes.TextAreaClass +
+ + 0 + affiliation + 23 + affiliation + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + avatar + 20 + Avatar + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + blog + 9 + Blog + 60 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + blogfeed + 10 + Blog Feed + 60 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + comment + 11 + Comment + 5 + 40 + 0 + com.xpn.xwiki.objects.classes.TextAreaClass + + + 0 + company + 8 + Company + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + default_language + 7 + Default Language + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + select + yesno + displayHiddenDocuments + 17 + Display Hidden Documents + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + 0 + select + 0 + editor + 14 + Default Editor + 0 + + ,| + 1 + 0 + ---|Text|Wysiwyg + com.xpn.xwiki.objects.classes.StaticListClass + + + 0 + email + 3 + e-Mail + 30 + 0 + /^(([^@\s]+)@((?:[-a-zA-Z0-9]+\.)+[a-zA-Z]{2,}))?$/ + com.xpn.xwiki.objects.classes.EmailClass + + + 0 + first_name + 1 + First Name + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + imaccount + 13 + imaccount + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + 0 + select + 0 + imtype + 12 + IM Type + 0 + + ,| + 1 + 0 + ---|AIM|Yahoo|Jabber|MSN|Skype|ICQ + com.xpn.xwiki.objects.classes.StaticListClass + + + 0 + last_name + 2 + Last Name + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + password + 4 + Password + 10 + 0 + com.xpn.xwiki.objects.classes.PasswordClass + + + 0 + phone + 21 + Phone + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + referral + 24 + referral + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + skin + 19 + skin + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + {{velocity}} +#if ($xcontext.action == 'inline' || $xcontext.action == 'edit') + {{html}} + #if($xwiki.jodatime) + <select id='$prefix$name' name='$prefix$name'> + <option value="" #if($value == $tz)selected="selected"#end>$services.localization.render('XWiki.XWikiPreferences_timezone_default')</option> + #foreach($tz in $xwiki.jodatime.getServerTimezone().getAvailableIDs()) + <option value="$tz" #if($value == $tz)selected="selected"#end>$tz</option> + #end + </select> + #else + <input id='$prefix$name' name='$prefix$name' type="text" value="$!value"/> + #end + {{/html}} +#else + $!value +#end +{{/velocity}} + + 0 + timezone + 18 + Timezone + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + 0 + select + 0 + usertype + 15 + User type + 0 + + ,| + 1 + 0 + Simple|Advanced + com.xpn.xwiki.objects.classes.StaticListClass + + + 0 + validkey + 5 + Validation Key + 10 + 0 + com.xpn.xwiki.objects.classes.PasswordClass + +
+ + + XWiki.ClassSheetBinding + + + + + + + + + + 0 + sheet + 1 + 0 + Sheet + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + XWiki.XWikiUsers + 0 + XWiki.ClassSheetBinding + a099ae40-73fb-427d-82e1-6b6088eba0f4 + + XWikiUserSheet + + + + + XWiki.DocumentSheetBinding + + + + + + + + + + 0 + sheet + 1 + 0 + Sheet + 30 + 0 + + + com.xpn.xwiki.objects.classes.StringClass + + + XWiki.XWikiUsers + 0 + XWiki.DocumentSheetBinding + dababa48-1a6c-4a80-9c1c-60b7bcdbd64f + + ClassSheet + + + +
diff --git a/war/src/main/webapp/resources/js/xwiki/usersandgroups/nonactiveusers.js b/war/src/main/webapp/resources/js/xwiki/usersandgroups/nonactiveusers.js new file mode 100644 index 00000000..d6ecdb27 --- /dev/null +++ b/war/src/main/webapp/resources/js/xwiki/usersandgroups/nonactiveusers.js @@ -0,0 +1,496 @@ +/** + * This is a copy of usersandgroups.js. It has some minor modifications. + * @type {void|*|HTMLOptionElement|HTMLImageElement|XMLHttpRequest|XDomainRequest} + */ + +MSCheckbox = Class.create({initialize: function (d, c, f, b, e, a) +{ + this.table = e; + this.idx = a; + if (this.table && this.idx && this.table.fetchedRows[this.idx]) { + this.currentUorG = this.table.fetchedRows[this.idx].fullname; + this.isUserInGroup = this.table.fetchedRows[this.idx].isuseringroup + } else { + this.currentUorG = window.unregUser; + this.isUserInGroup = false + } + this.domNode = $(d); + this.right = c; + this.saveUrl = f; + this.defaultState = b; + this.state = b; + this.states = [0, 1, 2]; + this.nrstates = this.states.length; + this.images = ["$xwiki.getSkinFile('js/xwiki/usersandgroups/img/none.png')", + "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/allow.png')", + "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/deny1.png')"]; + this.labels = ["", "", ""]; + this.draw(this.state); + this.attachEvents() +}, draw: function (b) +{ + while (this.domNode.childNodes.length > 0) { + this.domNode.removeChild(this.domNode.firstChild) + } + var a = document.createElement("img"); + a.src = this.images[b]; + this.domNode.appendChild(a); + if (this.labels[b] != "") { + var c = document.createElement("span"); + c.appendChild(document.createTextNode(this.labels[b])); + this.domNode.appendChild(c) + } +}, next: function () +{ + this.state = (this.state + 1) % this.nrstates; + if (this.table != undefined) { + delete this.table.fetchedRows[this.idx] + } + this.draw(this.state) +}, createClickHandler: function (a) +{ + return function () + { + if (a.req) { + return + } + var e = ""; + var d = (a.state + 1) % a.nrstates; + if (a.currentUorG == window.currentUser) { + if (d == 2) { + var c = "$escapetool.javascript($services.localization.render('rightsmanager.denyrightforcurrentuser'))".replace("__right__", + a.right); + if (!confirm(c)) { + var f = "$escapetool.javascript($services.localization.render('rightsmanager.clearrightforcurrentuserinstead'))".replace("__right__", + a.right); + if (confirm(f)) { + e = "clear"; + a.state = 2; + d = 0 + } else { + return + } + } + } else { + if (d == 0) { + var f = "$escapetool.javascript($services.localization.render('rightsmanager.clearrightforcurrentuser'))".replace("__right__", + a.right); + if (!confirm(f)) { + return + } + } + } + } else { + if (a.isUserInGroup || + (window.currentUser == "XWiki.XWikiGuest" && a.currentUorG == "XWiki.XWikiAllGroup")) + { + if (d == 2) { + var c = "$escapetool.javascript($services.localization.render('rightsmanager.denyrightforgroup'))".replace(/__right__/g, + a.right); + c = c.replace("__name__", a.currentUorG); + if (!confirm(c)) { + var f = "$escapetool.javascript($services.localization.render('rightsmanager.clearrightforgroupinstead'))".replace(/__right__/g, + a.right); + f = f.replace("__name__", a.currentUorG); + if (confirm(f)) { + e = "clear"; + a.state = 2; + d = 0 + } else { + return + } + } + } else { + if (d == 0) { + var f = "$escapetool.javascript($services.localization.render('rightsmanager.clearrightforgroup'))".replace(/__right__/g, + a.right); + f = f.replace("__name__", a.currentUorG); + if (!confirm(f)) { + return + } + } + } + } else { + if (a.right == "admin") { + if (d == 2) { + var c = "$escapetool.javascript($services.localization.render('rightsmanager.denyrightforuorg'))".replace("__right__", + a.right); + c = c.replace("__name__", a.currentUorG); + if (!confirm(c)) { + return + } + } else { + if (d == 0) { + var f = "$escapetool.javascript($services.localization.render('rightsmanager.clearrightforuorg'))".replace("__right__", + a.right); + f = f.replace("__name__", a.currentUorG); + if (!confirm(f)) { + return + } + } + } + } + } + } + if (e == "") { + if (d == 0) { + e = "clear" + } else { + if (d == 1) { + e = "allow" + } else { + e = "deny" + } + } + } + var b = a.saveUrl + "&action=" + e + "&right=" + a.right; + a.req = new Ajax.Request(b, {method: "get", onSuccess: function (h) + { + if (h.responseText.strip() == "SUCCESS") { + a.next() + } else { + alert("$services.localization.render('platform.core.rightsManagement.saveFailure')"); + var g = unescape(window.location.pathname); + window.location.href = g + } + }, onFailure: function () + { + alert("$services.localization.render('platform.core.rightsManagement.ajaxFailure')") + }, onComplete: function () + { + delete a.req + }}) + } +}, attachEvents: function () +{ + Event.observe(this.domNode, "click", this.createClickHandler(this)) +}}); +function displayUsers(s, j, r, b) +{ + var d = s.userurl; + var f = s.usersaveurl; + var l = s.userinlineurl; + var g = s.wikiname; + var e = s.docurl; + var n = document.createElement("tr"); + var h = document.createElement("td"); + if (g == "local") { + var o = document.createElement("a"); + o.href = d; + o.appendChild(document.createTextNode(s.username)); + h.appendChild(o) + } else { + h.appendChild(document.createTextNode(s.username)) + } + h.className = "username"; + n.appendChild(h); + var k = document.createElement("td"); + k.appendChild(document.createTextNode(s.firstname)); + n.appendChild(k); + var m = document.createElement("td"); + m.appendChild(document.createTextNode(s.lastname)); + n.appendChild(m); + var c = document.createElement("td"); + c.className = "manage"; + if (g == "local") { + var a = document.createElement("img"); + a.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/allow.png")'; + Event.observe(a, "click", approveUserOrGroup(j, r, s.fullname, "user", b)); + a.className = "icon-manage"; + c.appendChild(a); + var p = document.createElement("img"); + p.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/edit.png")'; + p.title = "$services.localization.render('edit')"; + Event.observe(p, "click", editUserOrGroup(l, f, e)); + p.className = "icon-manage"; + c.appendChild(p); + var q = document.createElement("img"); + if (s.grayed == "true") { + q.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/clearg.png")'; + q.className = "icon-manageg" + } else { + q.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/clear.png")'; + Event.observe(q, "click", deleteUserOrGroup(j, r, s.fullname, "user", b)); + q.className = "icon-manage" + } + q.title = "$services.localization.render('delete')"; + c.appendChild(q) + } + n.appendChild(c); + return n +} +function displayGroups(r, k, q, b) +{ + var d = r.userurl; + var l = r.userinlineurl; + var f = r.usersaveurl; + var h = r.wikiname; + var e = r.docurl; + var m = document.createElement("tr"); + var j = document.createElement("td"); + if (h == "local") { + var n = document.createElement("a"); + n.href = d; + n.appendChild(document.createTextNode(r.username)); + j.appendChild(n) + } else { + j.appendChild(document.createTextNode(r.username)) + } + j.className = "username"; + m.appendChild(j); + var g = document.createElement("td"); + if (h == "local") { + g.appendChild(document.createTextNode(r.members)) + } else { + g.appendChild(document.createTextNode("-")) + } + m.appendChild(g); + var c = document.createElement("td"); + c.className = "manage"; + if (h == "local") { + var p = document.createElement("img"); + p.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/clear.png")'; + p.title = "$services.localization.render('delete')"; + Event.observe(p, "click", deleteUserOrGroup(k, q, r.fullname, "group", b)); + p.className = "icon-manage"; + var o = document.createElement("img"); + o.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/edit.png")'; + o.title = "$services.localization.render('edit')"; + Event.observe(o, "click", editUserOrGroup(l, f, e)); + o.className = "icon-manage"; + c.appendChild(o); + c.appendChild(p) + } + m.appendChild(c); + return m +} +function displayMembers(l, e, k, b) +{ + var f = document.createElement("tr"); + var d = document.createElement("td"); + var h = document.createTextNode(l.prettyname); + if (l.wikiname == "local") { + var g = document.createElement("a"); + g.href = l.memberurl; + g.appendChild(h); + d.appendChild(g) + } else { + d.appendChild(h) + } + d.className = "username"; + f.appendChild(d); + if (k.action == "inline") { + var c = document.createElement("td"); + c.className = "manage"; + var j = document.createElement("img"); + if (l.grayed == "true") { + j.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/clearg.png")'; + j.className = "icon-manageg" + } else { + j.src = '$xwiki.getSkinFile("js/xwiki/usersandgroups/img/clear.png")'; + Event.observe(j, "click", deleteMember(e, k, l.fullname, l.docurl, b)); + j.className = "icon-manage" + } + j.title = "$services.localization.render('delete')"; + c.appendChild(j); + f.appendChild(c) + } + return f +} +function displayUsersAndGroups(o, e, m, l, b) +{ + var c = o.userurl; + var f = m.json.uorg; + var n = o.allows; + var k = o.denys; + var g = window.docviewurl + "?xpage=saverights&clsname=" + m.json.clsname + "&fullname=" + o.fullname + "&uorg=" + + f; + if (b != undefined) { + g += "&form_token=" + b + } + var h = document.createElement("tr"); + var d = document.createElement("td"); + if (o.wikiname == "local") { + var j = document.createElement("a"); + j.href = c; + j.appendChild(document.createTextNode(o.username)); + d.appendChild(j) + } else { + d.appendChild(document.createTextNode(o.username)) + } + d.className = "username"; + h.appendChild(d); + window.activeRights.each(function (i) + { + if (i) { + var q = document.createElement("td"); + q.className = "rights"; + var p = 0; + if (n.match("\\b" + i + "\\b")) { + p = 1 + } else { + if (k.match("\\b" + i + "\\b")) { + p = 2 + } + } + var a = new MSCheckbox(q, i, g, p, m, e); + h.appendChild(q) + } + }); + return h +} +function editUserOrGroup(a, c, b) +{ + var a1 = a, c1 = c, b1 = b; + return function () + { + window.lb = new Lightbox(a, c, b) + } +} +function deleteUserOrGroup(c, d, b, a, e) +{ + return function () + { + var f = "?xpage=deleteuorg&docname=" + b; + if (e != undefined) { + f += "&form_token=" + e + } + if (a == "user") { + if (confirm("$escapetool.javascript($services.localization.render('rightsmanager.confirmdeleteuser'))".replace("__name__", + b))) + { + new Ajax.Request(f, {method: "get", onSuccess: function (g) + { + d.deleteRow(c) + }}) + } + } else { + if (confirm("$escapetool.javascript($services.localization.render('rightsmanager.confirmdeletegroup'))".replace("__name__", + b))) + { + new Ajax.Request(f, {method: "get", onSuccess: function (g) + { + d.deleteRow(c) + }}) + } + } + } +} +function approveUserOrGroup(c, d, b, a, e) +{ + return function () + { + var f = "$xwiki.getURL('XWiki.ManualAccountValidation', 'get', 'outputSyntax=plain')&xwikiname=" + b; + if (confirm("Are you use you want to approve this user __name__?".replace("__name__", + b))) + { + new Ajax.Request(f, {method: "get", onSuccess: function (g) + { + if (g.responseText == "true") { + d.deleteRow(c) + } + }}) + } + } +} +function deleteMember(b, c, a, e, d) +{ + return function () + { + var f = e + "?xpage=deletegroupmember&fullname=" + a; + if (d != undefined) { + f += "&form_token=" + d + } + if (confirm("$escapetool.javascript($services.localization.render('rightsmanager.confirmdeletemember'))")) { + new Ajax.Request(f, {method: "get", onSuccess: function (g) + { + c.deleteRow(b) + }}) + } + } +} +function makeAddHandler(b, c, a) +{ + return function () + { + window.lb = new Lightbox(b, c, a) + } +} +function setBooleanPropertyFromLiveCheckbox(c, b, a, d) +{ + return function () + { + var k = "$xwiki.getURL('XWiki.XWikiPreferences', 'save')"; + var h = "XWiki.XWikiPreferences"; + var j = "0"; + if (b != undefined && b.length > 0) { + k = b + } + if (a != undefined && a.length > 0) { + h = a + } + if (d != undefined) { + j = d + } + var e = c; + var f = "yes"; + var g = "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/allow-black.png')"; + var l = "1"; + if (c.getAttribute("alt") == "yes") { + f = "no"; + g = "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/none.png')"; + l = "0" + } + var i = {}; + i.parameters = {}; + i.parameters[h + "_" + j + "_" + c.id] = l; + i.parameters["ajax"] = "1"; + i.onSuccess = function () + { + e.alt = f; + e.src = g + }; + new Ajax.Request(k, i) + } +} +function setGuestExtendedRights(a) +{ + return function () + { + var c = '$xwiki.getURL("XWiki.XWikiPreferences", "save")'; + var b = a; + if (a.getAttribute("alt") == "yes") { + if (a.id.indexOf("view") > 0) { + new Ajax.Request(c, + {method: "post", parameters: {"XWiki.XWikiPreferences_0_authenticate_view": "0"}, onSuccess: function () + { + b.alt = "no"; + b.src = "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/none.png')" + }}) + } else { + new Ajax.Request(c, + {method: "post", parameters: {"XWiki.XWikiPreferences_0_authenticate_edit": "0"}, onSuccess: function () + { + b.alt = "no"; + b.src = "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/none.png')" + }}) + } + } else { + if (a.id.indexOf("view") > 0) { + new Ajax.Request(c, + {method: "post", parameters: {"XWiki.XWikiPreferences_0_authenticate_view": "1"}, onSuccess: function () + { + b.alt = "yes"; + b.src = "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/allow-black.png')" + }}) + } else { + new Ajax.Request(c, + {method: "post", parameters: {"XWiki.XWikiPreferences_0_authenticate_edit": "1"}, onSuccess: function () + { + b.alt = "yes"; + b.src = "$xwiki.getSkinFile('js/xwiki/usersandgroups/img/allow-black.png')" + }}) + } + } + } +}; diff --git a/war/src/main/webapp/resources/uicomponents/widgets/validation/uniquenessvalidation.js b/war/src/main/webapp/resources/uicomponents/widgets/validation/uniquenessvalidation.js new file mode 100644 index 00000000..7203ac61 --- /dev/null +++ b/war/src/main/webapp/resources/uicomponents/widgets/validation/uniquenessvalidation.js @@ -0,0 +1,99 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +/** + * This file can be easily modified for use with different parameters in different circumstances. However, since it is + * being used in a single place (for now), it is left fairly hardcoded. + * However, even in this state, it is fairly flexible. + */ +var XWiki = (function(XWiki) { + // Start XWiki augmentation + var widgets = XWiki.widgets = XWiki.widgets || {}; + + widgets.UniquenessValidator = Class.create({ + initialize : function(input, serviceUrl) { + this.input = input; + this.valid = true; + this.state = 'NEW'; + this.request = 0; + this.value = input.value; + this.serviceUrl = serviceUrl; + if (!this.input.__validation) { + this.input.__validation = new LiveValidation(this.input, {validMessage: '', wait : 500}); + } + this.input.__validation.add(this.validate.bind(this)); + }, + check : function() { + if (this.input.value != this.value) { + this.value = this.input.value; + this.state = 'CHECKING'; + new Ajax.Request(this.serviceUrl, { + parameters : { outputSyntax: 'plain', eid: this.value, id: XWiki.Model.serialize(new XWiki.DocumentReference(XWiki.currentDocument.wiki, XWiki.currentDocument.space, XWiki.currentDocument.page))}, + on200 : this.self.bindAsEventListener(this), + on403 : this.empty.bindAsEventListener(this), + on404 : this.available.bindAsEventListener(this), + on409 : this.exists.bindAsEventListener(this), + onComplete: this.responded.bindAsEventListener(this) + }); + } + }, + validate : function(value) { + if (this.state == 'DONE') { + this.value == value && (this.valid || Validate.fail("This identifier already exists")); + } + this.check(); + return true; + }, + self : function() { + this.valid = true; + }, + available : function() { + this.valid = true; + }, + empty : function() { + this.valid = false; + }, + exists : function() { + this.valid = false; + }, + responded : function() { + this.state = 'DONE'; + this.input.__validation.validate(); + } + }); + + var init = function(event) { + var serviceUrl = new XWiki.Document('UsernameValidation', 'PhenomeCentral').getURL('get'); + ((event && event.memo.elements) || [$('body')]).each(function(element) { + element.select('input.check-unique, .external_id input').each(function(input) { + if (!input.__uniqueness_validator) { + input.__uniqueness_validator = new XWiki.widgets.UniquenessValidator(input, serviceUrl); + } + }); + }); + return true; + }; + + (XWiki.domIsLoaded && init()) || document.observe("xwiki:dom:loaded", init); + document.observe('xwiki:dom:updated', init); + + // End XWiki augmentation. + return XWiki; +}(XWiki || {})); diff --git a/war/src/main/webapp/templates/registerinline.vm b/war/src/main/webapp/templates/registerinline.vm new file mode 100644 index 00000000..8b74588f --- /dev/null +++ b/war/src/main/webapp/templates/registerinline.vm @@ -0,0 +1,72 @@ +#if(!$xwiki.hasAccessLevel('view', 'PhenomeCentral.RegistrationWiki') || $xwiki.getDocument('PhenomeCentral.RegistrationWiki').isNew()) + ## Display the static content included in this template, as there's no override in the wiki +

$services.localization.render('core.register.title')

+ #if(!$reg || $reg < 0) +

$services.localization.render('core.register.welcome')

+ #end + #if($reg && $reg <= 0) + #if($reg == -2) + #error($services.localization.render('core.register.passwordMismatch')) + #elseif($reg == -3) + #error($services.localization.render('core.register.userAlreadyExists')) + #elseif($reg == -4) + #error($services.localization.render('core.register.invalidUsername')) + #elseif($reg == -8) + #error($services.localization.render('core.register.userAlreadyExists')) + #else + #error($services.localization.render('core.register.registerFailed', [$reg])) + #end + #elseif($reg) + #set($xwname = "XWiki.${request.xwikiname}") + #info($services.localization.render('core.register.successful', [$xwiki.getUserName($xwname), ${escapetool.xml($request.xwikiname)}])) + #end + #if(!$reg || $reg < 0) +
+
+ ## CSRF prevention + + + + + #set($class = $xwiki.getClass('XWiki.XWikiUsers')) + #set($obj = $class.newObject()) + #set($serverobj = $class.newObject()) + #set($discard = $doc.use('XWiki.XWikiUsers')) + #if($request.register_first_name) + $doc.set('first_name', $request.register_first_name) + #end + #if($request.register_last_name) + $doc.set('last_name', $request.register_last_name) + #end +
+ #set($prop = $class.first_name) +
+
$doc.displayEdit($prop, 'register_', $obj)
+ + #set($prop = $class.last_name) +
+
$doc.displayEdit($prop, 'register_', $obj)
+ +
+
+ + #set($prop = $class.password) +
+
$doc.displayEdit($prop, 'register_', $obj).replace('type=', 'autocomplete="off" type=')
+ +
+
$doc.displayEdit($prop, 'register2_', $obj).replace('type=', 'autocomplete="off" type=')
+ + #set($prop = $class.email) +
+
$doc.displayEdit($prop, 'register_', $obj)
+
+
+
+
+ #end +#else + ## An override exists in the wiki, display it + #set($doc = $xwiki.getDocument('PhenomeCentral.RegistrationWiki')) + $xwiki.includeTopic('PhenomeCentral.RegistrationWiki', false) +#end