mirror of
https://github.com/overleaf/overleaf.git
synced 2024-09-16 02:52:31 -04:00
Merge and fix external forms
This commit is contained in:
commit
aa8969c652
14 changed files with 157 additions and 1114 deletions
|
@ -102,14 +102,25 @@ module.exports = ProjectController =
|
||||||
projects = ProjectController._buildProjectList results.projects[0], results.projects[1], results.projects[2]
|
projects = ProjectController._buildProjectList results.projects[0], results.projects[1], results.projects[2]
|
||||||
ProjectController._injectProjectOwners projects, (error, projects) ->
|
ProjectController._injectProjectOwners projects, (error, projects) ->
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
res.render 'project/list', {
|
|
||||||
|
viewModel = {
|
||||||
title:'Your Projects'
|
title:'Your Projects'
|
||||||
priority_title: true
|
priority_title: true
|
||||||
projects: projects
|
projects: projects
|
||||||
tags: tags
|
tags: tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if Settings?.algolia?.institutions?.app_id? and Settings?.algolia?.institutions?.api_key?
|
||||||
|
viewModel.showUserDetailsArea = true
|
||||||
|
viewModel.algolia_api_key = Settings.algolia.institutions.api_key
|
||||||
|
viewModel.algolia_app_id = Settings.algolia.institutions.app_id
|
||||||
|
else
|
||||||
|
viewModel.showUserDetailsArea = false
|
||||||
|
|
||||||
|
res.render 'project/list', viewModel
|
||||||
timer.done()
|
timer.done()
|
||||||
|
|
||||||
|
|
||||||
loadEditor: (req, res, next)->
|
loadEditor: (req, res, next)->
|
||||||
timer = new metrics.Timer("load-editor")
|
timer = new metrics.Timer("load-editor")
|
||||||
if !Settings.editorIsOpen
|
if !Settings.editorIsOpen
|
||||||
|
|
|
@ -31,8 +31,10 @@ html(itemscope, itemtype='http://schema.org/Product')
|
||||||
script(type="text/javascript").
|
script(type="text/javascript").
|
||||||
window.csrfToken = "#{csrfToken}";
|
window.csrfToken = "#{csrfToken}";
|
||||||
|
|
||||||
|
script(src=jsPath+'libs/jquery.js')
|
||||||
script(src=jsPath+'libs/angular-1.2.17.js')
|
script(src=jsPath+'libs/angular-1.2.17.js')
|
||||||
script(src=jsPath+'libs/moment-2.4.0.js')
|
script(src=jsPath+'libs/moment-2.4.0.js')
|
||||||
|
script(src=jsPath+'libs/underscore-1.3.3.js')
|
||||||
block scripts
|
block scripts
|
||||||
|
|
||||||
- if (typeof(bodyClasses) == "undefined")
|
- if (typeof(bodyClasses) == "undefined")
|
||||||
|
|
|
@ -6,12 +6,18 @@ block scripts
|
||||||
projects: !{JSON.stringify(projects)},
|
projects: !{JSON.stringify(projects)},
|
||||||
tags: !{JSON.stringify(tags)}
|
tags: !{JSON.stringify(tags)}
|
||||||
};
|
};
|
||||||
|
window.algolia = {
|
||||||
|
institutions: {
|
||||||
|
app_id: '#{algolia_app_id}',
|
||||||
|
api_key: '#{algolia_api_key}'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
block content
|
block content
|
||||||
.content.content-alt(ng-controller="ProjectPageController")
|
.content.content-alt(ng-controller="ProjectPageController")
|
||||||
.container
|
.container
|
||||||
.row
|
.row
|
||||||
.col-md-2
|
.col-md-3
|
||||||
#newProject.dropdown
|
#newProject.dropdown
|
||||||
a.btn.btn-primary.dropdown-toggle(
|
a.btn.btn-primary.dropdown-toggle(
|
||||||
href="#",
|
href="#",
|
||||||
|
@ -80,7 +86,66 @@ block content
|
||||||
.row-spaced
|
.row-spaced
|
||||||
a(href="/user/bonus").btn.btn-info Upgrade Account
|
a(href="/user/bonus").btn.btn-info Upgrade Account
|
||||||
|
|
||||||
.col-md-10
|
- if (showUserDetailsArea)
|
||||||
|
.row-spaced#userProfileInformation(ng-cloak)
|
||||||
|
div(ng-controller="UpdateForm").userProfileInformationArea
|
||||||
|
div(ng-hide="hidePersonalInfoSection").alert.alert-info
|
||||||
|
div(ng-show="percentComplete >= 100")
|
||||||
|
h4 100% complete, well done!
|
||||||
|
div(ng-hide="percentComplete >= 100")
|
||||||
|
h4 Your profile is
|
||||||
|
strong {{percentComplete}}%
|
||||||
|
| complete
|
||||||
|
|
||||||
|
.progress
|
||||||
|
.bar.bar-success(ng-style="{'width' : (percentComplete+'%')}")
|
||||||
|
|
||||||
|
button#completeUserProfileInformation.btn.btn-primary(
|
||||||
|
ng-hide="formVisable",
|
||||||
|
ng-click="showForm()"
|
||||||
|
) Complete now
|
||||||
|
|
||||||
|
div(ng-show="formVisable")
|
||||||
|
form(enctype='multipart/form-data', method='post')
|
||||||
|
.form-group
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
name='first_name',
|
||||||
|
ng-model="userInfoForm.first_name",
|
||||||
|
ng-blur="sendUpdate()",
|
||||||
|
placeholder="First Name",
|
||||||
|
focus-input="formVisable"
|
||||||
|
)
|
||||||
|
.form-group
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
name='last_name',
|
||||||
|
ng-model="userInfoForm.last_name",
|
||||||
|
ng-blur="sendUpdate()",
|
||||||
|
placeholder='Last Name'
|
||||||
|
)
|
||||||
|
.form-group#institution_auto_complete
|
||||||
|
autocomplete(
|
||||||
|
ng-model="userInfoForm.institution",
|
||||||
|
data="institutions",
|
||||||
|
ng-blur="sendUpdate()",
|
||||||
|
on-type="updateInstitutionsList",
|
||||||
|
attr-placeholder="Institution",
|
||||||
|
attr-inputclass="form-control"
|
||||||
|
)
|
||||||
|
.form-group
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
name='role',
|
||||||
|
ng-model="userInfoForm.role",
|
||||||
|
placeholder='Role',
|
||||||
|
ng-blur="sendUpdate()",
|
||||||
|
list="_roles"
|
||||||
|
)
|
||||||
|
datalist#_roles
|
||||||
|
option(ng-repeat='role in roles') {{role}}
|
||||||
|
|
||||||
|
.col-md-9
|
||||||
.container-fluid
|
.container-fluid
|
||||||
.row
|
.row
|
||||||
.col-md-12
|
.col-md-12
|
||||||
|
|
|
@ -8,14 +8,22 @@ block content
|
||||||
.card
|
.card
|
||||||
.page-header
|
.page-header
|
||||||
h1 Login
|
h1 Login
|
||||||
.messageArea
|
form(async-form="login", action='/login')
|
||||||
form.validate#loginForm(enctype='multipart/form-data', method='post')
|
|
||||||
input(name='_csrf', type='hidden', value=csrfToken)
|
input(name='_csrf', type='hidden', value=csrfToken)
|
||||||
input(name='redir', type='hidden', value=redir)
|
input(name='redir', type='hidden', value=redir)
|
||||||
|
form-messages
|
||||||
.form-group
|
.form-group
|
||||||
input#email.email.required.form-control(type='email', autofocus="autofocus", name='email', placeholder='email@example.com')
|
input.form-control(
|
||||||
|
type='email',
|
||||||
|
name='email',
|
||||||
|
placeholder='email@example.com'
|
||||||
|
)
|
||||||
.form-group
|
.form-group
|
||||||
input#password.required.form-control(type='password', name='password', placeholder='********')
|
input.form-control(
|
||||||
|
type='password',
|
||||||
|
name='password',
|
||||||
|
placeholder='********'
|
||||||
|
)
|
||||||
.actions
|
.actions
|
||||||
button.btn-primary.btn#login(type='submit') Login
|
button.btn-primary.btn(type='submit') Login
|
||||||
a#passwordReset.pull-right(href='/user/password/reset') Forgot your password?
|
a.pull-right(href='/user/password/reset') Forgot your password?
|
||||||
|
|
|
@ -9,10 +9,20 @@ block content
|
||||||
.page-header
|
.page-header
|
||||||
h1 Password Reset
|
h1 Password Reset
|
||||||
.messageArea
|
.messageArea
|
||||||
form.validate#passwordReset(method='post')
|
form(
|
||||||
|
async-form="password-reset-request",
|
||||||
|
action="/user/password/reset"
|
||||||
|
)
|
||||||
input(type="hidden", name="_csrf", value=csrfToken)
|
input(type="hidden", name="_csrf", value=csrfToken)
|
||||||
|
form-messages
|
||||||
|
.alert.alert-success(ng-show="success")
|
||||||
|
| You have been sent an email to complete your password reset.
|
||||||
.form-group
|
.form-group
|
||||||
label(for='email') Please enter your email address
|
label(for='email') Please enter your email address
|
||||||
input.email.required.form-control(type='email', name='email', placeholder='email@example.com')
|
input.form-control(
|
||||||
|
type='email',
|
||||||
|
name='email',
|
||||||
|
placeholder='email@example.com'
|
||||||
|
)
|
||||||
.actions
|
.actions
|
||||||
button.btn.btn-primary.btn.btn-large(type='submit') Request password reset
|
button.btn.btn-primary(type='submit') Request password reset
|
||||||
|
|
|
@ -18,16 +18,16 @@ block content
|
||||||
.card
|
.card
|
||||||
.page-header
|
.page-header
|
||||||
h1 Register
|
h1 Register
|
||||||
.messageArea
|
form(async-form="register", action="/register")
|
||||||
form#registerFormShort(method="post")
|
|
||||||
input(name='_csrf', type='hidden', value=csrfToken)
|
input(name='_csrf', type='hidden', value=csrfToken)
|
||||||
input(name='redir', type='hidden', value=redir)
|
input(name='redir', type='hidden', value=redir)
|
||||||
|
form-messages
|
||||||
.form-group
|
.form-group
|
||||||
label(for='email') Email
|
label(for='email') Email
|
||||||
input#email.email.required.form-control(type='email', name='email', value='#{new_email}')
|
input.form-control(type='email', name='email', value='#{new_email}')
|
||||||
.form-group
|
.form-group
|
||||||
label(for='password') Password
|
label(for='password') Password
|
||||||
input#password.required.form-control(type='password', name='password')
|
input.form-control(type='password', name='password')
|
||||||
.actions
|
.actions
|
||||||
button#registerButton.btn-primary.btn(type='submit') Register
|
button.btn-primary.btn(type='submit') Register
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,26 @@ block content
|
||||||
.card
|
.card
|
||||||
.page-header
|
.page-header
|
||||||
h1 Reset your password
|
h1 Reset your password
|
||||||
.messageArea
|
form(
|
||||||
form.validate#setPasswordReset(method='post')
|
async-form="password-reset",
|
||||||
|
action="/user/password/set"
|
||||||
|
)
|
||||||
input(type="hidden", name="_csrf", value=csrfToken)
|
input(type="hidden", name="_csrf", value=csrfToken)
|
||||||
|
form-messages
|
||||||
|
.alert.alert-success(ng-show="success")
|
||||||
|
| Your password has been reset.
|
||||||
|
a(href='/login') Login here
|
||||||
|
|
||||||
.form-group
|
.form-group
|
||||||
input.password.required.form-control(type='password', name='password', placeholder='new password')
|
input.form-control(
|
||||||
input(type="hidden", name="passwordResetToken", value=passwordResetToken)
|
type='password',
|
||||||
|
name='password',
|
||||||
|
placeholder='new password'
|
||||||
|
)
|
||||||
|
input(
|
||||||
|
type="hidden",
|
||||||
|
name="passwordResetToken",
|
||||||
|
value=passwordResetToken
|
||||||
|
)
|
||||||
.actions
|
.actions
|
||||||
button.btn.btn-primary.btn.btn-large(type='submit') Set new password
|
button.btn.btn-primary(type='submit') Set new password
|
|
@ -1,5 +1,6 @@
|
||||||
define [
|
define [
|
||||||
"project-list"
|
"project-list"
|
||||||
"user-details"
|
"user-details"
|
||||||
|
"directives/asyncForm"
|
||||||
], () ->
|
], () ->
|
||||||
angular.bootstrap(document.body, ["SharelatexApp"])
|
angular.bootstrap(document.body, ["SharelatexApp"])
|
|
@ -2,8 +2,8 @@ define [
|
||||||
"base"
|
"base"
|
||||||
"../libs/algolia"
|
"../libs/algolia"
|
||||||
], (App, algolia)->
|
], (App, algolia)->
|
||||||
App.factory "Institutions", ->
|
app.factory "Institutions", ->
|
||||||
new AlgoliaSearch("SK53GL4JLY", "1606ccef5b70ac44680b61e6b0285126").initIndex("institutions")
|
new AlgoliaSearch(window.algolia.institutions.app_id, window.algolia.institutions.api_key).initIndex("institutions")
|
||||||
|
|
||||||
App.directive "focusInput", ($timeout) ->
|
App.directive "focusInput", ($timeout) ->
|
||||||
return (scope, element, attr) ->
|
return (scope, element, attr) ->
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
require [
|
|
||||||
"libs/jquery.storage"
|
|
||||||
"libs/bootstrap"
|
|
||||||
], ()->
|
|
||||||
$('tr.clickable').click (event)->
|
|
||||||
window.location = $(event.target).closest('tr').attr("href")
|
|
||||||
|
|
||||||
$('.dropdown-toggle').dropdown()
|
|
||||||
# $('.tabs').tab('show')
|
|
||||||
|
|
||||||
$(".carousel").carousel()
|
|
||||||
|
|
||||||
$("#scribtexModal").modal()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
define [
|
|
||||||
"libs/bootstrap"
|
|
||||||
"forms"
|
|
||||||
], ()->
|
|
||||||
$(document).ready ()->
|
|
File diff suppressed because it is too large
Load diff
|
@ -296,6 +296,16 @@ input[type="checkbox"],
|
||||||
.form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);
|
.form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .form-control.ng-invalid {
|
||||||
|
// border-color: @state-danger-text;
|
||||||
|
// .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
|
||||||
|
// &:focus {
|
||||||
|
// border-color: darken(@state-danger-text, 10%);
|
||||||
|
// @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@state-danger-text, 20%);
|
||||||
|
// .box-shadow(@shadow);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
// Static form control text
|
// Static form control text
|
||||||
//
|
//
|
||||||
|
|
|
@ -18,10 +18,14 @@ describe "UserInfoController", ->
|
||||||
updatePersonalInfo: sinon.stub()
|
updatePersonalInfo: sinon.stub()
|
||||||
@sanitizer = escape:(v)->v
|
@sanitizer = escape:(v)->v
|
||||||
sinon.spy @sanitizer, "escape"
|
sinon.spy @sanitizer, "escape"
|
||||||
|
@UserGetter = {}
|
||||||
|
|
||||||
|
|
||||||
@UserInfoController = SandboxedModule.require modulePath, requires:
|
@UserInfoController = SandboxedModule.require modulePath, requires:
|
||||||
"./UserGetter": @UserGetter = {}
|
"./UserGetter": @UserGetter
|
||||||
"./UserUpdater": @UserUpdater
|
"./UserUpdater": @UserUpdater
|
||||||
"./UserDeleter": @UserDeleter
|
"./UserDeleter": @UserDeleter
|
||||||
|
"logger-sharelatex": log:->
|
||||||
"sanitizer":@sanitizer
|
"sanitizer":@sanitizer
|
||||||
|
|
||||||
@req = new MockRequest()
|
@req = new MockRequest()
|
||||||
|
@ -33,7 +37,9 @@ describe "UserInfoController", ->
|
||||||
@user =
|
@user =
|
||||||
_id: ObjectId()
|
_id: ObjectId()
|
||||||
@req.user = @user
|
@req.user = @user
|
||||||
|
@req.session.user = @user
|
||||||
@UserInfoController.sendFormattedPersonalInfo = sinon.stub()
|
@UserInfoController.sendFormattedPersonalInfo = sinon.stub()
|
||||||
|
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, @user)
|
||||||
@UserInfoController.getLoggedInUsersPersonalInfo(@req, @res, @next)
|
@UserInfoController.getLoggedInUsersPersonalInfo(@req, @res, @next)
|
||||||
|
|
||||||
it "should call sendFormattedPersonalInfo", ->
|
it "should call sendFormattedPersonalInfo", ->
|
||||||
|
@ -105,6 +111,8 @@ describe "UserInfoController", ->
|
||||||
email: "doug@sharelatex.com"
|
email: "doug@sharelatex.com"
|
||||||
password: "should-not-get-included"
|
password: "should-not-get-included"
|
||||||
signUpDate: new Date()
|
signUpDate: new Date()
|
||||||
|
role:"student"
|
||||||
|
institution:"sheffield"
|
||||||
@UserInfoController._formatPersonalInfo @user, (error, info) =>
|
@UserInfoController._formatPersonalInfo @user, (error, info) =>
|
||||||
expect(info).to.deep.equal {
|
expect(info).to.deep.equal {
|
||||||
id: @user._id.toString()
|
id: @user._id.toString()
|
||||||
|
@ -112,6 +120,8 @@ describe "UserInfoController", ->
|
||||||
last_name: @user.last_name
|
last_name: @user.last_name
|
||||||
email: @user.email
|
email: @user.email
|
||||||
signUpDate: @user.signUpDate
|
signUpDate: @user.signUpDate
|
||||||
|
role: @user.role
|
||||||
|
institution: @user.institution
|
||||||
}
|
}
|
||||||
|
|
||||||
describe "setPersonalInfo", ->
|
describe "setPersonalInfo", ->
|
||||||
|
|
Loading…
Reference in a new issue