--------------------------------------------------------------------------------
-- Title: WikiEditorService.lua
-- Description: Like a square peg in a round hole
-- Author: Raphaël Szwarc http://alt.textdrive.com/lua/
-- Creation Date: January 30, 2007
-- Legal: Copyright (C) 2007 Raphaël Szwarc
-- Under the terms of the MIT License
-- http://www.opensource.org/licenses/mit-license.html
--------------------------------------------------------------------------------
-- import dependencies
local HTTP = require( 'HTTP' )
local HTTPExtra = require( 'HTTPExtra' )
local HTTPService = require( 'HTTPService' )
local Template = require( 'Template' )
local WikiContent = require( 'WikiContent' )
local WikiDate = require( 'WikiDate' )
local WikiFinder = require( 'WikiFinder' )
local WikiRecent = require( 'WikiRecent' )
local WikiSearch = require( 'WikiSearch' )
local WikiContentService = require( 'WikiContentService' )
local WikiService = require( 'WikiService' )
local BaseLink = WikiService.BaseLink
local DateLink = WikiService.DateLink
local FeedLink = WikiService.FeedLink
local IndexLink = WikiService.IndexLink
local Encode = WikiService.Encode
local Path = WikiService.Path
local os = require( 'os' )
local assert = assert
local getmetatable = getmetatable
local ipairs = ipairs
local pairs = pairs
local require = require
local setmetatable = setmetatable
local tonumber = tonumber
local tostring = tostring
local type = type
--------------------------------------------------------------------------------
-- WikiEditorService
--------------------------------------------------------------------------------
module( 'WikiEditorService' )
_VERSION = '1.0'
local self = setmetatable( _M, {} )
local meta = getmetatable( self )
--------------------------------------------------------------------------------
-- Utilities
--------------------------------------------------------------------------------
local function Message( self )
local aMessage = self.message
if aMessage then
local someTypes = { check = 'error', count = 'error', time = 'warning', title = 'warning', text = 'warning', token = 'error', version = 'warning' }
local aType = someTypes[ self.type ] or 'warning'
local WikiMessage = require( 'WikiMessage' )
local aMessage = WikiMessage( aMessage, aType )
return aMessage
end
end
local function Token()
local Token = require( 'Token' )
local aToken = Token( HTTP.request.url )
local aList = { 'check', 'count', 'time', 'title', 'text', 'token', 'version' }
local aMap = {}
for _, aValue in ipairs( aList ) do
aMap[ aValue ] = aToken[ aValue ]
end
return aMap
end
local function Context()
local someTypes = { check = nil, count = 'number', time = 'number', title = 'string', text = 'string', token = 'string', version = 'number' }
local someFunctions = { check = nil, count = tonumber, time = tonumber, title = tostring, text = tostring, token = tostring, version = tonumber }
local aToken = Token()
local aParameter = HTTP.request.parameter
local aContext = {}
for aKey, aValue in pairs( aToken ) do
local aType = someTypes[ aKey ]
local aFunction = someFunctions[ aKey ]
local aValue = aParameter[ aValue ]
if aValue and aFunction then
aValue = aFunction( aValue )
end
if aValue and tostring( aValue ):len() == 0 then
aValue = nil
end
if not aType or type( aValue ) == aType then
aContext[ aKey ] = aValue
end
end
return aContext
end
local function Validate( aName )
local aContext = Context()
if aContext.check then
return false, 'check', 'Invalid data. Try again.'
end
if not aContext.count or aContext.count < 1 then
return false, 'count', 'Invalid data. Try again.'
end
if not aContext.time or ( os.time() - aContext.time ) < 3 then
return false, 'time', 'Too fast. Try again, but slowly.'
end
if not aContext.title or not WikiContent[ aContext.title ] then
return false, 'title', 'Empty title. Try to add some text.'
end
if not aContext.text or not WikiContent[ aContext.text ] then
return false, 'text', 'Empty content. Try to add some text.'
end
if not aContext.token or aContext.token ~= Token()[ 'token' ] then
return false, 'token', 'Invalid data. Try again.'
end
if not aContext.version or aContext.version ~= WikiContent( aName ).version then
return false, 'version', 'Version mismatch. Try to edit the latest version.'
end
return true
end
local function ID()
local aRequest = HTTP.request
local aScheme = aRequest.url.scheme or 'http'
local aUser = WikiContent[ aRequest.authorization.user or 'anonymous' ]
local anAddress = WikiContent[ aRequest.address or '127.0.0.1' ]:gsub( '-', '.' )
local aHost = aRequest.host or 'localhost'
local anID = ( '%s://%s:%s@%s' ):format( aScheme, aUser, anAddress, aHost )
return anID
end
local function Save( aName, aContext )
local aName = assert( aName )
local aContext = assert( aContext )
local aVersion = assert( aContext.version )
local aNewVersion = aVersion + 1
local aContent = WikiContent( aName, aVersion )
if not aContent.exists then
aNewVersion = aContent.version
end
if aContent.data.title ~= aContext.title
or aContent.text ~= aContext.text then
local aNewContent = WikiContent( aName, aNewVersion )
aNewContent.title = aContext.title
aNewContent.text = aContext.text
aNewContent.by = ID()
aNewContent()
WikiDate[ aNewContent.name ] = aNewContent.creation
WikiFinder[ aNewContent.name ] = true
WikiRecent[ aNewContent.name ] = aNewContent.modification
WikiSearch[ aNewContent.name ] = aNewContent.name
return aNewContent
end
return aContent
end
local function Title( aContent, aContext )
return aContext.title or aContent.data.title
end
local function Text( aContent, aContext )
return aContext.text or aContent.text
end
local function Version( aContent, aContext )
return aContext.version or aContent.lastVersion
end
local function TitleLink( aContent )
local aTitle = Encode( aContent.data.title )
if aContent.exists then
local aLink = Encode( HTTP.request.url.path( 'revision' ) )
return ( '%s' ):format( aLink, aTitle )
end
return aTitle
end
local function ControlLink( aContent )
if aContent.exists then
local aLink = Encode( HTTP.request.url.path( 'control' ) )
return ( '
' ):format( aLink )
end
end
local function FileCount( aContent )
if aContent.exists then
local aCount = 0
for aFile in aContent.file do
aCount = aCount + 1
end
return aCount
end
end
local function FileLink( aContent )
local aCount = FileCount( aContent )
if aCount then
local anImage = '
'
local aLink = HTTP.request.url.path( 'file' )
local aTitle = ''
if aCount == 0 then
aTitle = 'Add a file'
elseif aCount == 1 then
aTitle = '1 file'
else
aTitle = ( '%d files' ):format( aCount )
end
aLink = Encode( aLink )
aTitle = Encode( aTitle )
return ( '