Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/master' into terminal
Browse files Browse the repository at this point in the history
  • Loading branch information
notnotdrew committed Feb 17, 2017
2 parents 937767a + cc41094 commit 1c47a21
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 213 deletions.
102 changes: 18 additions & 84 deletions lib/auth.coffee
Original file line number Diff line number Diff line change
@@ -1,46 +1,19 @@
url = require 'url'
https = require 'https'
remote = require 'remote'
shell = require 'shell'
path = require 'path'
version = require './version'
fetch = require './fetch'
_token = require './token'
config = require './config'
BrowserWindow = remote.BrowserWindow
{learnCo} = require './config'
{BrowserWindow} = require 'remote'

workspaceView = atom.views.getView(atom.workspace)
AUTH_URL = "#{learnCo}/api/v1/users/me?ile_version=#{version}"

confirmOauthToken = (token) ->
return new Promise (resolve, reject) ->
try
authRequest = https.get
host: 'learn.co'
path: '/api/v1/users/me?ile_version=' + atom.appVersion
headers:
'Authorization': 'Bearer ' + token
, (response) ->
body = ''

response.on 'data', (d) ->
body += d

response.on 'error', reject

response.on 'end', ->
try
parsed = JSON.parse(body)

if parsed.email
resolve parsed
else
resolve false
catch
reject false

authRequest.on 'error', (err) ->
reject err

catch err
reject err
headers = new Headers({'Authorization': "Bearer #{token}"})

fetch(AUTH_URL, {headers}).then (data) ->
if data.email? then data else false

githubLogin = () ->
new Promise (resolve, reject) ->
Expand All @@ -56,7 +29,7 @@ githubLogin = () ->

# hide window immediately after login
webContents.on 'will-navigate', (e, url) ->
win.hide() if url.match("#{config.learnCo}/users/auth/github/callback")
win.hide() if url.match("#{learnCo}/users/auth/github/callback")

webContents.on 'did-get-redirect-request', (e, oldURL, newURL) ->
return unless newURL.match(/ide_token/)
Expand All @@ -67,8 +40,12 @@ githubLogin = () ->
win.destroy()
resolve()

if not win.loadURL("#{config.learnCo}/ide/token?ide_config=true")
promptManualEntry()
if not win.loadURL("#{learnCo}/ide/token?ide_config=true")
atom.notifications.warning 'Learn IDE: connectivity issue',
detail: "The editor is unable to connect to #{learnCo}. Are you connected to the internet?"
buttons: [
{text: 'Try again', onDidClick: -> learnSignIn()}
]

learnSignIn = () ->
new Promise (resolve, reject) ->
Expand Down Expand Up @@ -103,53 +80,10 @@ learnSignIn = () ->
win.destroy()
githubLogin().then(resolve)

if not win.loadURL("#{config.learnCo}/ide/sign_in?ide_onboard=true")
if not win.loadURL("#{learnCo}/ide/sign_in?ide_onboard=true")
win.destroy()
githubLogin.then(resolve)

promptManualEntry = ->
oauthPrompt = document.createElement 'div'
oauthPrompt.setAttribute 'style', 'width:100%; text-align: center;'

oauthLabel = document.createElement 'div'
oauthLabel.setAttribute 'style', 'margin-top: 12px; font-weight: bold; font-size: 12px;'
oauthLabel.appendChild document.createTextNode 'Please enter your Learn OAuth Token'
tokenLinkDiv = document.createElement 'div'
tokenText = document.createTextNode 'Get your token here: '
tokenLink = document.createElement 'a'
tokenLink.title = "#{config.learnCo}/ide/token"
tokenLink.href = "#{config.learnCo}/ide/token"
tokenLink.setAttribute 'style', 'text-decoration: underline;'
tokenLink.appendChild document.createTextNode "#{config.learnCo}/ide/token"
tokenLinkDiv.appendChild tokenText
tokenLinkDiv.appendChild tokenLink
oauthPrompt.appendChild oauthLabel
oauthLabel.appendChild tokenLinkDiv

invalidLabel = document.createElement 'label'
invalidLabel.setAttribute 'style', 'opacity: 0;'
invalidLabel.appendChild document.createTextNode 'Invalid token. Please try again.'
oauthPrompt.appendChild invalidLabel
input = document.createElement 'input'
input.setAttribute 'style', 'width: 100%; text-align: center;'
input.classList.add 'native-key-bindings'
oauthPrompt.appendChild input

panel = atom.workspace.addModalPanel item: oauthPrompt
input.focus()

input.addEventListener 'keypress', (e) =>
if e.which is 13
token = input.value.trim()
confirmOauthToken(token).then (res) ->
if res
_token.set(token)
panel.destroy()
atom.commands.dispatch(workspaceView, 'learn-ide:toggle-terminal')
return true
else
invalidLabel.setAttribute 'style', 'color: red; opacity: 100;'

githubLogout = ->
win = new BrowserWindow(show: false)
win.webContents.on 'did-finish-load', -> win.show()
Expand All @@ -158,7 +92,7 @@ githubLogout = ->
learnLogout = ->
win = new BrowserWindow(show: false)
win.webContents.on 'did-finish-load', -> win.destroy()
win.loadURL("#{config.learnCo}/sign_out")
win.loadURL("#{learnCo}/sign_out")

window.logout = ->
_token.unset()
Expand Down
4 changes: 2 additions & 2 deletions lib/fetch.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = fetchWrapper = (url) ->
fetch(url)
module.exports = fetchWrapper = (url, init) ->
fetch(url, init)
.then (response) -> response.text()
.then (body) -> JSON.parse(body)

29 changes: 29 additions & 0 deletions lib/notifications/submission.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
path = require 'path'
fetch = require '../fetch'
{learnCo} = require '../config'
submissionRegistry = []
cachedLessonTitles = {}

getLessonTitle = (lessonID) ->
title = cachedLessonTitles[lessonID]

if title?
return Promise.resolve(title)

fetch("#{learnCo}/api/v1/lessons/#{lessonID}").then ({title}) =>
cachedLessonTitles[lessonID] = title || 'Learn IDE'
return title

icon = (passing) ->
pass = path.resolve(__dirname, '..', '..', 'static', 'images', 'pass.png')
fail = path.resolve(__dirname, '..', '..', 'static', 'images', 'fail.png')
if passing is 'true' then pass else fail

module.exports = ({submission_id, lesson_id, passing, message}) ->
if not submissionRegistry.includes(submission_id)
submissionRegistry.push(submission_id)

getLessonTitle(lesson_id).then (title) =>
notif = new Notification(title, {body: message, icon: icon(passing)})
notif.onclick = -> notif.close()

149 changes: 23 additions & 126 deletions lib/notifier.coffee
Original file line number Diff line number Diff line change
@@ -1,140 +1,37 @@
https = require 'https'
querystring = require 'querystring'
{EventEmitter} = require 'events'
AtomSocket = require 'atom-socket'
atomHelper = require './atom-helper'
path = require 'path'
fetch = require './fetch'
{learnCo} = require './config'

notificationStrategies =
submission: require('./notifications/submission')

module.exports =
class Notifier extends EventEmitter
constructor: (authToken) ->
@authToken = authToken
@notifRegistry = []
@notifTitles = {}
@notificationTypes = ['submission']
class Notifier
constructor: (token) ->
@token = token

activate: ->
@authenticate().then ({id}) =>
@connect(id)

@on 'notification-debug', (msg) ->
console.log('NOTIFICATION DEBUG:', msg)

@on 'new-notification', (data) =>
if atomHelper.isLastFocusedWindow()
console.log('NOTIFICATION:', data)

notif = new Notification data.displayTitle,
body: data.message
icon: @getIcon(data)

notif.onclick = ->
notif.close()

@authenticate()
.then =>
@connect()
.catch (e) ->
console.error 'error connecting to notification service:', e

getIcon: (data) ->
pass = path.resolve(__dirname, '..', 'static', 'images', 'pass.png')
fail = path.resolve(__dirname, '..', 'static', 'images', 'fail.png')
if data.passing is 'true' then pass else fail

authenticate: =>
return new Promise (resolve, reject) =>
https.get
host: 'learn.co'
path: '/api/v1/users/me'
headers:
'Authorization': 'Bearer ' + @authToken
, (response) =>
console.log 'NOTIFICATION RESPONSE:', response
body = ''

response.on 'data', (d) ->
body += d

response.on 'error', ->
reject Error('Cannot subscribe to notifications. Problem parsing response.')

response.on 'end', =>
try
parsed = JSON.parse(body)

if parsed.id
@id = parsed.id

resolve this
else
reject Error('Cannot subscribe to notifications. Not authorized.')
catch
reject Error('Cannot subscribe to notifications. Problem parsing response.')

connect: =>
@connection = new AtomSocket('notif', 'wss://push.flatironschool.com:9443/ws/fis-user-' + @id)

@connection.on 'open', (e) =>
this.emit 'notification-debug', 'Listening for notifications...'

@connection.on 'message', (data) =>
try
rawData = JSON.parse(data)
eventData = querystring.parse rawData.text
uid = @eventUid eventData

if @notificationTypes.indexOf(eventData.type) >= 0 && !(@notifRegistry.indexOf(uid) >= 0)
@notifRegistry.push(uid)

@getDisplayTitle(eventData).then (title) =>
eventData.displayTitle = title
this.emit 'new-notification', eventData
catch err
console.log err
this.emit 'notification-debug', 'Error creating notification.'

getDisplayTitle: (event) =>
# NOTE THAT FOR NOW THIS ONLY WORKS WITH LESSONS
return new Promise (resolve, reject) =>
try
displayTitle = @notifTitles[event.lesson_id]

if displayTitle
resolve displayTitle
else
https.get
host: 'learn.co'
path: '/api/v1/lessons/' + event.lesson_id
, (response) =>
body = ''

response.on 'data', (d) ->
body += d

response.on 'error', ->
@notifTitles[event.lesson_id] = 'Learn IDE'
resolve 'Learn IDE'
authenticate: ->
headers = new Headers({'Authorization': "Bearer #{@token}"})
fetch("#{learnCo}/api/v1/users/me", {headers})

response.on 'end', =>
try
parsed = JSON.parse(body)
connect: (userID) ->
@ws = new AtomSocket('notif', "wss://push.flatironschool.com:9443/ws/fis-user-#{userID}")

if parsed.title
@notifTitles[event.lesson_id] = parsed.title
resolve parsed.title
else
@notifTitles[event.lesson_id] = 'Learn IDE'
resolve 'Learn IDE'
catch
@notifTitles[event.lesson_id] = 'Learn IDE'
resolve 'Learn IDE'
catch err
console.log err
@ws.on 'message', (msg) =>
@parseMessage(JSON.parse(msg))

eventUid: (event) =>
switch event.type
when 'submission' then parseInt(event.submission_id)
else null
parseMessage: ({text}) ->
if atomHelper.isLastFocusedWindow()
data = querystring.parse(text)
callback = notificationStrategies[data.type]
callback?(data)

deactivate: ->
@connection.close()
@ws.close()

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "learn-ide",
"version": "2.4.0-beta5",
"version": "2.4.0",
"atomVersion": "1.14.2",
"main": "./lib/learn-ide",
"urlMain": "./lib/url-handler",
Expand Down

0 comments on commit 1c47a21

Please sign in to comment.