mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-26 22:13:32 -04:00
Employer signup works
This commit is contained in:
parent
6644c6a9ee
commit
4f6f845c2d
8 changed files with 102 additions and 37 deletions
app
lib
schemas/models
styles
templates
views
server/users
|
@ -23,6 +23,13 @@ module.exports = LinkedInHandler = class LinkedInHandler extends CocoClass
|
|||
me.set("linkedIn", @linkedInData)
|
||||
console.log "LinkedIn data is #{@linkedInData}"
|
||||
|
||||
constructEmployerAgreementObject: (cb) =>
|
||||
IN.API.Profile("me")
|
||||
.fields(["positions","public-profile-url","id","first-name","last-name","email-address"])
|
||||
.error(cb)
|
||||
.result (profiles) =>
|
||||
cb null, profiles.values[0]
|
||||
|
||||
|
||||
destroy: ->
|
||||
super()
|
||||
|
|
|
@ -53,7 +53,7 @@ UserSchema = c.object {},
|
|||
|
||||
#Internationalization stuff
|
||||
preferredLanguage: {type: 'string', default: 'en', 'enum': c.getLanguageCodeArray()}
|
||||
|
||||
|
||||
signedCLA: c.date({title: 'Date Signed the CLA'})
|
||||
wizard: c.object {},
|
||||
colorConfig: c.object {additionalProperties: c.colorConfig()}
|
||||
|
@ -109,6 +109,11 @@ UserSchema = c.object {},
|
|||
jobProfileApproved: {title: 'Job Profile Approved', type: 'boolean', description: 'Whether your profile has been approved by CodeCombat.'}
|
||||
jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: "CodeCombat's notes on the candidate.", format: 'markdown', default: ''}
|
||||
employerAt: c.shortString {description: "If given employer permissions to view job candidates, for which employer?"}
|
||||
signedEmployerAgreement: c.object {},
|
||||
linkedinID: c.shortString {title:"LinkedInID", description: "The user's LinkedIn ID when they signed the contract."}
|
||||
date: c.date {title: "Date signed employer agreement"}
|
||||
data: c.object
|
||||
|
||||
|
||||
c.extendBasicProperties UserSchema, 'user'
|
||||
|
||||
|
|
|
@ -138,8 +138,8 @@ a[data-toggle="modal"]
|
|||
.signin-text
|
||||
font-size: 15px
|
||||
padding-bottom: 10px
|
||||
.login-link
|
||||
cursor: pointer
|
||||
.login-link
|
||||
cursor: pointer
|
||||
|
||||
|
||||
// Bigger versions of some Bootstrap icons
|
||||
|
|
|
@ -12,9 +12,11 @@ block content
|
|||
span(data-i18n="employers.candidates_count_many") many
|
||||
|
|
||||
span(data-i18n="employers.candidates_count_suffix") highly skilled and vetted developers looking for work.
|
||||
h3
|
||||
a(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/employer_signup", data-i18n="employers.contact_george") Contact George to see our candidates
|
||||
if !isEmployer
|
||||
|
||||
h3
|
||||
a(title='Contact', tabindex=-1, data-toggle="coco-modal", data-target="modal/employer_signup") Click here to see candidates
|
||||
|
||||
if candidates.length
|
||||
table.table.table-condensed.table-hover.table-responsive.tablesorter
|
||||
thead
|
||||
|
|
|
@ -4,49 +4,57 @@ block modal-header-content
|
|||
if userIsAnonymous || !userIsAuthorized
|
||||
h3(data-i18n="employer_signup.title") Sign up to hire CodeCombat players!
|
||||
else
|
||||
h3 Hiring Contract
|
||||
h3 CodeCombat Placement Agreement
|
||||
|
||||
block modal-body-content
|
||||
if userIsAnonymous
|
||||
h4(data-i18n="employer_signup.sub_heading") Let us find your next brilliant developers.
|
||||
|
||||
p Create an account to get started!
|
||||
.form
|
||||
.form-group
|
||||
label.control-label(for="signup-email", data-i18n="general.email") Email
|
||||
input#signup-email.form-control.input-large(name="email",type="email")
|
||||
.form-group
|
||||
label.control-label(for="signup-password", data-i18n="general.password") Password
|
||||
input#signup-password.input-large.form-control(name="password", type="password")
|
||||
if userIsAuthorized
|
||||
| You appear to be authorized on CodeCombat with LinkedIn.
|
||||
else
|
||||
h4(data-i18n="employer_signup.sub_heading") Let us find your next brilliant developers.
|
||||
p Create an account to get started!
|
||||
.form
|
||||
.form-group
|
||||
label.control-label(for="signup-email", data-i18n="general.email") Email
|
||||
input#signup-email.form-control.input-large(name="email",type="email")
|
||||
.form-group
|
||||
label.control-label(for="signup-password", data-i18n="general.password") Password
|
||||
input#signup-password.input-large.form-control(name="password", type="password")
|
||||
else if !userIsAuthorized
|
||||
.modal-footer.linkedin
|
||||
p Please sign into your LinkedIn account to verify your identity.
|
||||
script(type="in/Login" id="linkedInAuthButton" data-onAuth="contractCallback")
|
||||
|
||||
else
|
||||
| We (CodeCombat) are providing you (the Company) access to information about our best players. In exchange, you agree to pay us 15% of the first year's annualized starting base salary for any person that you hire on a full time basis through this site. That 15% is due on the first date that our candidate is employed and is 100% refundable for 90 days after that date if the candidate doesn't remain employed at the company for any reason.
|
||||
| Please agree to our terms before accessing our candidates.
|
||||
br
|
||||
br
|
||||
b Who we are:
|
||||
| CodeCombat is a programming game that both teaches and vets programmers. If you accept this agreement, we will let you hire the most talented developers on our platform.
|
||||
br
|
||||
br
|
||||
b Placement fee:
|
||||
| If you hire our any of our players, you agree to pay us 15% of the candidate's first year annualized starting base salary. The fee is due on the first day that the candidate is employed and is 100% refundable for up to 90 day if the candidate doesn't remain employed at the company for any reason.
|
||||
br
|
||||
br
|
||||
b Interns are free:
|
||||
| We will not bill you for interns and part time hires (remote or onsite) hired through this site, provided they do not become full time hires within 1 year of their start date. If they do become full time hires within 1 year of their start date, we will invoice you 15% of their first year's annualized starting base salary on their first day of full time employment. For these hires, the 90 day guarantee does not apply.
|
||||
br
|
||||
br
|
||||
| You must keep all of the information you access on this site confidential. That means you cannot share it with third parties and will only use it for recruiting.
|
||||
br
|
||||
br
|
||||
| We will invoice this account via email and you agree to pay within 30 days of that email being sent.
|
||||
br
|
||||
br
|
||||
| Neither you or CodeCombat will be liable for any damages that result from this contract.
|
||||
|
||||
| By clicking Agree, you are agreeing to CodeCombat's Placement Agreement on behalf of your company. You also consent to CodeCombat storing basic LinkedIn profile data for verification purposes, including your name, email, public profile URL, and work history.
|
||||
block modal-footer
|
||||
if userIsAnonymous && !userisAuthorized
|
||||
.modal-footer.linkedin
|
||||
b.signin-text Sign in with LinkedIn to complete the registration process.
|
||||
script(type="in/Login" id="linkedInAuthButton" data-onAuth="contractCallback")
|
||||
br
|
||||
br
|
||||
| Already have a CodeCombat account?
|
||||
a.login-link(data-toggle="coco-modal", data-target="modal/login") Log in to continue!
|
||||
if userIsAnonymous
|
||||
if !userIsAuthorized
|
||||
.modal-footer.linkedin
|
||||
b.signin-text Sign in with LinkedIn to complete the registration process.
|
||||
script(type="in/Login" id="linkedInAuthButton" data-onAuth="contractCallback")
|
||||
br
|
||||
br
|
||||
| Already have a CodeCombat account?
|
||||
a.login-link(data-toggle="coco-modal", data-target="modal/login") Log in to continue!
|
||||
else
|
||||
.modal-footer.linkedin
|
||||
a.login-link(data-toggle="coco-modal", data-target="modal/login") Please log in to continue.
|
||||
else if !userIsAnonymous && !userIsAuthorized
|
||||
.modal-footer.linkedin
|
||||
| We will record your name and work history for verification purposes.
|
||||
|
|
|
@ -2,6 +2,7 @@ View = require 'views/kinds/RootView'
|
|||
template = require 'templates/employers'
|
||||
app = require 'application'
|
||||
User = require 'models/User'
|
||||
{me} = require 'lib/auth'
|
||||
CocoCollection = require 'models/CocoCollection'
|
||||
EmployerSignupView = require 'views/modal/employer_signup_modal'
|
||||
|
||||
|
@ -27,6 +28,9 @@ module.exports = class EmployersView extends View
|
|||
getRenderData: ->
|
||||
c = super()
|
||||
c.candidates = @candidates.models
|
||||
userPermissions = me.get('permissions') || []
|
||||
|
||||
c.isEmployer = _.contains userPermissions, "employer"
|
||||
c.moment = moment
|
||||
c
|
||||
|
||||
|
|
|
@ -54,7 +54,21 @@ module.exports = class EmployerSignupView extends View
|
|||
context
|
||||
|
||||
agreeToContract: ->
|
||||
|
||||
application.linkedinHandler.constructEmployerAgreementObject (err, profileData) =>
|
||||
if err? then return handleAgreementFailure err
|
||||
$.ajax
|
||||
url: "/db/user/#{me.id}/agreeToEmployerAgreement"
|
||||
data: profileData
|
||||
type: "POST"
|
||||
success: @handleAgreementSuccess
|
||||
error: @handleAgreementFailure
|
||||
|
||||
handleAgreementSuccess: (result) ->
|
||||
me.fetch()
|
||||
window.location.reload()
|
||||
|
||||
handleAgreementFailure: (error) ->
|
||||
|
||||
createAccount: (e) =>
|
||||
console.log "Tried to create account!"
|
||||
e.stopPropagation()
|
||||
|
@ -84,7 +98,7 @@ module.exports = class EmployerSignupView extends View
|
|||
|
||||
|
||||
recordUserDetails: (e) =>
|
||||
console.log "Record user details here!"
|
||||
#TODO: refactor this out
|
||||
@render()
|
||||
|
||||
destroy: ->
|
||||
|
|
|
@ -14,7 +14,7 @@ LevelSessionHandler = require '../levels/sessions/level_session_handler'
|
|||
serverProperties = ['passwordHash', 'emailLower', 'nameLower', 'passwordReset']
|
||||
privateProperties = [
|
||||
'permissions', 'email', 'firstName', 'lastName', 'gender', 'facebookID',
|
||||
'gplusID', 'music', 'volume', 'aceConfig', 'employerAt'
|
||||
'gplusID', 'music', 'volume', 'aceConfig', 'employerAt', 'signedEmployerAgreement'
|
||||
]
|
||||
candidateProperties = [
|
||||
'jobProfile', 'jobProfileApproved', 'jobProfileNotes'
|
||||
|
@ -182,6 +182,7 @@ UserHandler = class UserHandler extends Handler
|
|||
|
||||
getByRelationship: (req, res, args...) ->
|
||||
return @agreeToCLA(req, res) if args[1] is 'agreeToCLA'
|
||||
return @agreeToEmployerAgreement(req,res) if args[1] is 'agreeToEmployerAgreement'
|
||||
return @avatar(req, res, args[0]) if args[1] is 'avatar'
|
||||
return @getNamesByIDs(req, res) if args[1] is 'names'
|
||||
return @nameToID(req, res, args[0]) if args[1] is 'nameToID'
|
||||
|
@ -231,7 +232,31 @@ UserHandler = class UserHandler extends Handler
|
|||
return @sendDatabaseError(res, err) if err
|
||||
documents = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)
|
||||
@sendSuccess(res, documents)
|
||||
|
||||
agreeToEmployerAgreement: (req, res) ->
|
||||
userIsAnonymous = req.user?.get('anonymous')
|
||||
if userIsAnonymous then return errors.unauthorized(res, "You need to be logged in to agree to the employer agreeement.")
|
||||
profileData = req.body
|
||||
#TODO: refactor this bit to make it more elegant
|
||||
if not profileData.id or not profileData.positions or not profileData.emailAddress or not profileData.firstName or not profileData.lastName
|
||||
return errors.badInput(res, "You need to have a more complete profile to sign up for this service.")
|
||||
@modelClass.findById(req.user.id).exec (err, user) =>
|
||||
if user.get('employerAt') or user.get('signedEmployerAgreement') or "employer" in user.get('permissions')
|
||||
return errors.conflict(res, "You already have signed the agreement!")
|
||||
#TODO: Search for the current position
|
||||
employerAt = profileData.positions.values[0].company.name
|
||||
signedEmployerAgreement =
|
||||
linkedinID: profileData.id
|
||||
date: new Date()
|
||||
data: profileData
|
||||
updateObject =
|
||||
"employerAt": employerAt
|
||||
"signedEmployerAgreement": signedEmployerAgreement
|
||||
$push: "permissions":'employer'
|
||||
|
||||
User.update {"_id": req.user.id}, updateObject, (err, result) =>
|
||||
if err? then return errors.serverError(res, "There was an issue updating the user object to reflect employer status: #{err}")
|
||||
res.send({"message": "The agreement was successful."})
|
||||
res.end()
|
||||
getCandidates: (req, res) ->
|
||||
authorized = req.user.isAdmin() or ('employer' in req.user.get('permissions'))
|
||||
since = (new Date((new Date()) - 2 * 30.4 * 86400 * 1000)).toISOString()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue