Upload new/changed images to GitHub when saving MD
This commit is contained in:
@@ -88,9 +88,11 @@ Key.Escape = 27
|
||||
Key.UpArrow = 38
|
||||
Key.DownArrow = 40
|
||||
|
||||
exports.GitHub = GitHub = {}
|
||||
GitHub.file = {}
|
||||
GitHub.file.itemDescription = _.template "/data/<%= modSlug %>/items/<%= itemSlug %>/item.cg"
|
||||
exports.GitHub = GitHub = {}
|
||||
GitHub.file = {}
|
||||
GitHub.file.itemDescription = {}
|
||||
GitHub.file.itemDescription.fileName = _.template "item.cg"
|
||||
GitHub.file.itemDescription.path = _.template "/data/<%= modSlug %>/items/<%= itemSlug %>"
|
||||
|
||||
exports.Login = Login = {}
|
||||
Login.authorizeUrl = _.template "https://github.com/login/oauth/authorize" +
|
||||
|
||||
@@ -6,6 +6,7 @@ All rights reserved.
|
||||
###
|
||||
|
||||
AdsenseController = require './adsense_controller'
|
||||
EditableFile = require '../models/editable_file'
|
||||
FullRecipeController = require './full_recipe_controller'
|
||||
ImageLoader = require './image_loader'
|
||||
Item = require '../models/item'
|
||||
@@ -42,7 +43,7 @@ module.exports = class ItemPageController extends PageController
|
||||
@imageLoader = options.imageLoader
|
||||
@modPack = options.modPack
|
||||
|
||||
@_editingFile = null
|
||||
@_descriptionFile = null
|
||||
@_itemSlug = options.itemSlug
|
||||
|
||||
@modPack.on Event.change, => @tryRefresh()
|
||||
@@ -155,13 +156,16 @@ module.exports = class ItemPageController extends PageController
|
||||
if not @model.item?
|
||||
return w.reject new Error 'must have an item'
|
||||
|
||||
@client.fetchFile path:GitHub.file.itemDescription modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item
|
||||
.then (response)=>
|
||||
@_editingFile = response.json.data
|
||||
@_editingFile.content = new Buffer(@_editingFile.content, 'base64').toString('utf8')
|
||||
pathArgs = modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item
|
||||
attributes =
|
||||
fileName: GitHub.file.itemDescription.fileName pathArgs
|
||||
path: GitHub.file.itemDescription.path pathArgs
|
||||
|
||||
if @_editingFile.content.length > 0
|
||||
@model.item.parse @_editingFile.content
|
||||
@_descriptionFile = new EditableFile attributes, client:@client
|
||||
@_descriptionFile.fetch()
|
||||
.then =>
|
||||
if @_descriptionFile.encodedData.length > 0
|
||||
@model.item.parse @_descriptionFile.getDecodedData 'utf8'
|
||||
else
|
||||
@model.item.description = ''
|
||||
|
||||
@@ -169,15 +173,18 @@ module.exports = class ItemPageController extends PageController
|
||||
|
||||
_endEditingDescription: ->
|
||||
oldDescription = @model.item.description
|
||||
promises = []
|
||||
|
||||
commitMessage = "User-submitted image for #{@model.item.name} from #{global.hostName}"
|
||||
for imageFile in @_descriptionController.imageFiles
|
||||
promises.push imageFile.save commitMessage
|
||||
|
||||
commitMessage = "User-submitted text for #{@model.item.name} from #{global.hostName}"
|
||||
@model.item.description = @_descriptionController.model
|
||||
@_descriptionFile.setDecodedData @model.item.unparse()
|
||||
promises.push @_descriptionFile.save commitMessage
|
||||
|
||||
args =
|
||||
content: new Buffer(@model.item.unparse(), 'utf8').toString('base64')
|
||||
message: "User-submitted text for #{@model.item.name}"
|
||||
path: GitHub.file.itemDescription modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item
|
||||
sha: @_editingFile.sha
|
||||
|
||||
@client.updateFile args
|
||||
w.all promises
|
||||
.catch (e)=>
|
||||
@model.item.description = oldDescription
|
||||
throw e
|
||||
|
||||
@@ -46,10 +46,7 @@ module.exports = class MarkdownImageController extends BaseController
|
||||
mimeType = match[1]
|
||||
encoding = match[2]
|
||||
|
||||
@model.set
|
||||
encodedData: encodedData
|
||||
status: MarkdownImage.Status.updateable
|
||||
|
||||
@model.encodedData = encodedData
|
||||
logger.info "loaded #{encodedData.length} bytes from #{file.name} as #{mimeType}"
|
||||
|
||||
logger.info "starting to read local file: #{file.name}"
|
||||
|
||||
@@ -25,7 +25,7 @@ module.exports = class MarkdownImageListController extends BaseController
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
getImageUrlForFile: (fileName)->
|
||||
@model.getImageUrlForFile fileName
|
||||
@model.getFile(fileName).imageUrl
|
||||
|
||||
reset: ->
|
||||
@model.reset()
|
||||
@@ -68,7 +68,7 @@ module.exports = class MarkdownImageListController extends BaseController
|
||||
super
|
||||
|
||||
refresh: ->
|
||||
@model.loadImages()
|
||||
@model.fetchImages()
|
||||
|
||||
@_controllers ?= []
|
||||
index = 0
|
||||
@@ -95,6 +95,5 @@ module.exports = class MarkdownImageListController extends BaseController
|
||||
return if newValid is oldValid
|
||||
|
||||
@_valid = newValid
|
||||
logger.debug "setting mic.valid to #{@_valid}"
|
||||
@trigger Event.change + ':valid', this, oldValid, newValid
|
||||
@trigger Event.change
|
||||
|
||||
@@ -104,7 +104,8 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
.then =>
|
||||
@state = State.confirming
|
||||
.catch (e)=>
|
||||
logger.error "failed to end editing: #{e}"
|
||||
message = if e.stack? then e.stack else e
|
||||
logger.error "failed to end editing: #{message}"
|
||||
@state = State.appologizing
|
||||
.delay @confirmDuration
|
||||
.then =>
|
||||
@@ -130,6 +131,9 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
@trigger Event.change + ':imageBase', this, oldImageBase, newImageBase
|
||||
@trigger Event.change, this
|
||||
|
||||
getImageFiles: ->
|
||||
return @_imageListController.model.all
|
||||
|
||||
getState: ->
|
||||
return @_state
|
||||
|
||||
@@ -143,9 +147,10 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
@_updateStateVisibility()
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
editable: {get:@prototype.isEditable}
|
||||
imageBase: {get:@prototype.getImageBase, set:@prototype.setImageBase}
|
||||
state: {get:@prototype.getState, set:@prototype.setState}
|
||||
editable: { get:@prototype.isEditable }
|
||||
imageBase: { get:@prototype.getImageBase, set:@prototype.setImageBase }
|
||||
imageFiles: { get:@prototype.getImageFiles }
|
||||
state: { get:@prototype.getState, set:@prototype.setState }
|
||||
|
||||
# BaseController Overrides #####################################################################
|
||||
|
||||
@@ -211,7 +216,6 @@ module.exports = class MarkdownSectionController extends BaseController
|
||||
|
||||
_updateButtonStates: ->
|
||||
for $button in [ @$previewButton, @$saveButton ]
|
||||
logger.debug "updating buttons based upon valid state: #{@_imageListController.valid}"
|
||||
if @_imageListController.valid
|
||||
$button.prop 'disabled', false
|
||||
else
|
||||
|
||||
@@ -23,9 +23,10 @@ if typeof(global) is 'undefined'
|
||||
window.global = window
|
||||
global = window.global
|
||||
|
||||
global.hostName = window.location.hostname
|
||||
global.logger = new Logger
|
||||
|
||||
switch window.location.hostname
|
||||
switch global.hostName
|
||||
when 'prerender.crafting-guide.com'
|
||||
global.env = 'prerender'
|
||||
logger.level = Logger.FATAL
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
###
|
||||
Crafting Guide - editable_file.coffee
|
||||
|
||||
Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseModel = require './base_model'
|
||||
{Event} = require '../constants'
|
||||
w = require 'when'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class EditableFile extends BaseModel
|
||||
|
||||
@MimeTypes = MimeTypes = [
|
||||
{ pattern:/\.cg$/i, text:'text/plain' }
|
||||
{ pattern:/\.png$/i, text:'image/png' }
|
||||
{ pattern:/\.gif$/i, text:'image/gif' }
|
||||
{ pattern:/\.jpg$/i, text:'image/jpeg' }
|
||||
{ pattern:/\.jpeg$/i, text:'image/jpeg' }
|
||||
]
|
||||
|
||||
@Status = Status = {
|
||||
'unknown': 'unknown'
|
||||
'checking': 'checking'
|
||||
'empty': 'empty'
|
||||
'clean': 'clean'
|
||||
'dirty': 'dirty'
|
||||
}
|
||||
|
||||
constructor: (attributes={}, options={})->
|
||||
attributes.fileName ?= ''
|
||||
attributes.path ?= ''
|
||||
attributes.sha ?= null
|
||||
attributes.status ?= Status.unknown
|
||||
super
|
||||
|
||||
@client = options.client
|
||||
@_encodedData = null
|
||||
|
||||
@on Event.change + ':fileName', => @_mimeType = null
|
||||
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
getDecodedData: (targetEncoding='utf8')->
|
||||
return new Buffer(@encodedData, 'base64').toString(targetEncoding)
|
||||
|
||||
setDecodedData: (text, sourceEncoding='utf8')->
|
||||
@encodedData = new Buffer(text, sourceEncoding).toString('base64')
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getDataAsText: ->
|
||||
if not @_dataAsText
|
||||
@_dataAsText = new Buffer(@encodedData, 'base64').toString('utf8')
|
||||
return @_dataAsText
|
||||
|
||||
getEncodedData: ->
|
||||
return @_encodedData
|
||||
|
||||
setEncodedData: (newEncodedData)->
|
||||
oldEncodedData = @_encodedData
|
||||
return if newEncodedData is oldEncodedData
|
||||
|
||||
@_encodedData = newEncodedData
|
||||
@_updateStatusForNewData()
|
||||
|
||||
@trigger Event.change + ':encodedData', this, oldEncodedData, newEncodedData
|
||||
@trigger Event.change, this
|
||||
|
||||
getFullPath: ->
|
||||
return "#{@path}/#{@fileName}"
|
||||
|
||||
getMimeType: ->
|
||||
if not @_mimeType?
|
||||
for mimeType in MimeTypes
|
||||
if mimeType.pattern.test @fileName
|
||||
@_mimeType = mimeType.text
|
||||
break
|
||||
|
||||
return @_mimeType
|
||||
|
||||
isValid: ->
|
||||
return @status in [ Status.clean, Status.dirty ]
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
encodedData: { get:@prototype.getEncodedData, set:@prototype.setEncodedData }
|
||||
fullPath: { get:@prototype.getFullPath }
|
||||
imageUrl: { get:@prototype.getImageUrl }
|
||||
mimeType: { get:@prototype.getMimeType }
|
||||
valid: { get:@prototype.isValid }
|
||||
|
||||
# BaseModel Overrides ##########################################################################
|
||||
|
||||
fetch: ->
|
||||
if not @client? then throw new Error 'EditableFile must be given a client to fetch with'
|
||||
|
||||
@status = Status.checking
|
||||
@client.fetchFile path:@fullPath
|
||||
.then (response)=>
|
||||
data = response.json.data
|
||||
|
||||
if data.sha?
|
||||
@encodedData = data.content
|
||||
@sha = data.sha
|
||||
else
|
||||
@status = Status.empty
|
||||
|
||||
return this
|
||||
|
||||
save: (commitMessage)->
|
||||
return w(true) if @status is Status.unchanged
|
||||
return w(true) unless @encodedData?
|
||||
if not @valid then return w.reject new Error "cannot save with an invalid status: #{@status}"
|
||||
|
||||
commitMessage ?= "User-submitted update to #{@fileName} from #{global.hostName}"
|
||||
@client.updateFile content:@encodedData, message:commitMessage, path:@fullPath, sha:@sha
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_updateStatusForNewData: ->
|
||||
switch @status
|
||||
when Status.unknown then @status = Status.dirty
|
||||
when Status.checking then @status = Status.clean
|
||||
when Status.empty then @status = Status.dirty
|
||||
when Status.clean then @status = Status.dirty
|
||||
@@ -5,82 +5,20 @@ Copyright (c) 2015 by Redwood Labs
|
||||
All rights reserved.
|
||||
###
|
||||
|
||||
BaseModel = require './base_model'
|
||||
_ = require 'underscore'
|
||||
{Event} = require '../constants'
|
||||
_ = require 'underscore'
|
||||
EditableFile = require './editable_file'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class MarkdownImage extends BaseModel
|
||||
|
||||
@MimeTypes = MimeTypes = [
|
||||
{pattern:/\.png$/i, text:'image/png'}
|
||||
{pattern:/\.gif$/i, text:'image/gif'}
|
||||
{pattern:/\.jpg$/i, text:'image/jpeg'}
|
||||
{pattern:/\.jpeg$/i, text:'image/jpeg'}
|
||||
]
|
||||
|
||||
@Status = Status = {
|
||||
'unknown': 'unknown'
|
||||
'checking': 'checking'
|
||||
'empty': 'empty'
|
||||
'creatable': 'creatable'
|
||||
'unchanged': 'unchanged'
|
||||
'updateable': 'updateable'
|
||||
}
|
||||
|
||||
constructor: (attributes={}, options={})->
|
||||
attributes.encodedData ?= null
|
||||
attributes.fileName ?= ''
|
||||
attributes.path ?= ''
|
||||
attributes.sha ?= null
|
||||
attributes.status ?= Status.unknown
|
||||
super
|
||||
|
||||
@client = options.client
|
||||
|
||||
@on Event.change + ':fileName', => @_mimeType = null
|
||||
module.exports = class MarkdownImage extends EditableFile
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
getFullPath: ->
|
||||
return "#{@path}/#{@fileName}"
|
||||
|
||||
getImageUrl: ->
|
||||
if @mimeType? and @encodedData?
|
||||
return "data:#{@mimeType};base64,#{@encodedData}"
|
||||
else
|
||||
return @fullPath
|
||||
|
||||
getMimeType: ->
|
||||
if not @_mimeType?
|
||||
for mimeType in MimeTypes
|
||||
if mimeType.pattern.test @fileName
|
||||
@_mimeType = mimeType.text
|
||||
break
|
||||
|
||||
return @_mimeType
|
||||
|
||||
isValid: ->
|
||||
return @status in [ Status.creatable, Status.unchanged, Status.updateable ]
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
fullPath: {get:@prototype.getFullPath}
|
||||
imageUrl: {get:@prototype.getImageUrl}
|
||||
mimeType: {get:@prototype.getMimeType}
|
||||
valid: {get:@prototype.isValid}
|
||||
|
||||
# BaseModel Overrides ##########################################################################
|
||||
|
||||
fetch: ->
|
||||
if not @client? then throw new Error 'MarkdownImage must be given a client to fetch with'
|
||||
|
||||
@status = Status.checking
|
||||
@client.fetchFile path:@fullPath
|
||||
.then (response)=>
|
||||
data = response.json.data
|
||||
|
||||
if data.sha?
|
||||
@set encodedData:data.content, sha:data.sha, status:Status.unchanged
|
||||
else
|
||||
@status = Status.empty
|
||||
|
||||
@@ -30,12 +30,10 @@ module.exports = class MarkdownImageList extends BaseModel
|
||||
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
getImageUrlForFile: (fileName)->
|
||||
result = @_images[fileName]?.imageUrl
|
||||
result ?= "#{@imageBase}/#{fileName}"
|
||||
return result
|
||||
getFile: (fileName)->
|
||||
return @_images[fileName]
|
||||
|
||||
loadImages: ->
|
||||
fetchImages: ->
|
||||
for fileName, image of @_images
|
||||
if image.status is MarkdownImage.Status.unknown
|
||||
image.fetch()
|
||||
|
||||
Reference in New Issue
Block a user