| 1 |
-------------------------------------------------------------------------------- |
|---|
| 2 |
-- Title: WikiContentFileService.lua |
|---|
| 3 |
-- Description: Like a square peg in a round hole |
|---|
| 4 |
-- Author: Raphaël Szwarc http://alt.textdrive.com/lua/ |
|---|
| 5 |
-- Creation Date: January 30, 2007 |
|---|
| 6 |
-- Legal: Copyright (C) 2007 Raphaël Szwarc |
|---|
| 7 |
-- Under the terms of the MIT License |
|---|
| 8 |
-- http://www.opensource.org/licenses/mit-license.html |
|---|
| 9 |
-------------------------------------------------------------------------------- |
|---|
| 10 |
|
|---|
| 11 |
-- import dependencies |
|---|
| 12 |
local HTTP = require( 'HTTP' ) |
|---|
| 13 |
|
|---|
| 14 |
local os = require( 'os' ) |
|---|
| 15 |
|
|---|
| 16 |
local getmetatable = getmetatable |
|---|
| 17 |
local require = require |
|---|
| 18 |
local setmetatable = setmetatable |
|---|
| 19 |
local tostring = tostring |
|---|
| 20 |
|
|---|
| 21 |
-------------------------------------------------------------------------------- |
|---|
| 22 |
-- WikiContentFileService |
|---|
| 23 |
-------------------------------------------------------------------------------- |
|---|
| 24 |
|
|---|
| 25 |
module( 'WikiContentFileService' ) |
|---|
| 26 |
_VERSION = '1.0' |
|---|
| 27 |
|
|---|
| 28 |
local self = setmetatable( _M, {} ) |
|---|
| 29 |
local meta = getmetatable( self ) |
|---|
| 30 |
|
|---|
| 31 |
-------------------------------------------------------------------------------- |
|---|
| 32 |
-- Utilities |
|---|
| 33 |
-------------------------------------------------------------------------------- |
|---|
| 34 |
|
|---|
| 35 |
local function ValidContent( aContent, aName ) |
|---|
| 36 |
if aContent |
|---|
| 37 |
and aContent.exists |
|---|
| 38 |
and ( '%s.txt' ):format( aContent.data.title ):lower() == aName:lower() then |
|---|
| 39 |
return true |
|---|
| 40 |
end |
|---|
| 41 |
end |
|---|
| 42 |
|
|---|
| 43 |
local function FindFile( aContent, aName ) |
|---|
| 44 |
aName = aName:lower() |
|---|
| 45 |
|
|---|
| 46 |
for aFile in aContent.file do |
|---|
| 47 |
if aFile.name == aName then |
|---|
| 48 |
return aFile |
|---|
| 49 |
end |
|---|
| 50 |
end |
|---|
| 51 |
end |
|---|
| 52 |
|
|---|
| 53 |
local function ValidFile( aContent, aName ) |
|---|
| 54 |
local aName = aName:lower(); |
|---|
| 55 |
local aReference = ( '%s/file/%s' ):format( aContent.name, aName ) |
|---|
| 56 |
local aFile = FindFile( aContent, aName ) |
|---|
| 57 |
|
|---|
| 58 |
if not aFile then |
|---|
| 59 |
return false |
|---|
| 60 |
end |
|---|
| 61 |
|
|---|
| 62 |
if not aContent.text:find( aReference, 1, true ) then |
|---|
| 63 |
local aTime = os.time() |
|---|
| 64 |
local anInterval = aTime - aFile.modification |
|---|
| 65 |
|
|---|
| 66 |
if anInterval < 3600 then |
|---|
| 67 |
return true |
|---|
| 68 |
else |
|---|
| 69 |
aFile.delete = true |
|---|
| 70 |
return false |
|---|
| 71 |
end |
|---|
| 72 |
end |
|---|
| 73 |
|
|---|
| 74 |
return true |
|---|
| 75 |
end |
|---|
| 76 |
|
|---|
| 77 |
local function DAVContentResource( aContent ) |
|---|
| 78 |
local aName = ( '%s.txt' ):format( aContent.data.title ) |
|---|
| 79 |
local aCreation = aContent.creation |
|---|
| 80 |
local aModification = aContent.modification |
|---|
| 81 |
local aSize = aContent.text:len() |
|---|
| 82 |
local aResource = { mode = 'file', creation = aCreation, modification = aModification, name = aName, size = aSize } |
|---|
| 83 |
|
|---|
| 84 |
return aResource |
|---|
| 85 |
end |
|---|
| 86 |
|
|---|
| 87 |
local function DAVFileResource( aContent, aName ) |
|---|
| 88 |
local aFile = FindFile( aContent, aName ) |
|---|
| 89 |
local aResource = { mode = aFile.mode, modification = aFile.modification, name = aFile.name, size = aFile.size } |
|---|
| 90 |
|
|---|
| 91 |
return aResource |
|---|
| 92 |
end |
|---|
| 93 |
|
|---|
| 94 |
local function DAVListIterator( aContent ) |
|---|
| 95 |
local anIterator = aContent.file |
|---|
| 96 |
|
|---|
| 97 |
return function() |
|---|
| 98 |
local aFile = anIterator() |
|---|
| 99 |
|
|---|
| 100 |
if aFile then |
|---|
| 101 |
local aResource = { mode = aFile.mode, modification = aFile.modification, name = aFile.name, size = aFile.size } |
|---|
| 102 |
|
|---|
| 103 |
return aResource |
|---|
| 104 |
end |
|---|
| 105 |
end |
|---|
| 106 |
end |
|---|
| 107 |
|
|---|
| 108 |
local function DAVListResource( aContent ) |
|---|
| 109 |
local anIterator = DAVListIterator( aContent ) |
|---|
| 110 |
local aModification = aContent.modification |
|---|
| 111 |
local aResource = { iterator = anIterator, mode = 'directory', modification = aModification, size = 0 } |
|---|
| 112 |
|
|---|
| 113 |
return aResource |
|---|
| 114 |
end |
|---|
| 115 |
|
|---|
| 116 |
local function DAVResource( aContent, aName ) |
|---|
| 117 |
if not aName then |
|---|
| 118 |
return DAVListResource( aContent ) |
|---|
| 119 |
elseif ValidContent( aContent, aName ) then |
|---|
| 120 |
return DAVContentResource( aContent ) |
|---|
| 121 |
elseif ValidFile( aContent, aName ) then |
|---|
| 122 |
return DAVFileResource( aContent, aName ) |
|---|
| 123 |
end |
|---|
| 124 |
end |
|---|
| 125 |
|
|---|
| 126 |
-------------------------------------------------------------------------------- |
|---|
| 127 |
-- Service methods |
|---|
| 128 |
-------------------------------------------------------------------------------- |
|---|
| 129 |
|
|---|
| 130 |
function self:get() |
|---|
| 131 |
local aContent = self.content |
|---|
| 132 |
local aName = self.name |
|---|
| 133 |
|
|---|
| 134 |
if aContent and aContent.exists and aName then |
|---|
| 135 |
local aName = aName:lower() |
|---|
| 136 |
|
|---|
| 137 |
if ValidContent( aContent, aName ) then |
|---|
| 138 |
HTTP.response.header[ 'content-type' ] = 'text/plain; charset=utf-8' |
|---|
| 139 |
|
|---|
| 140 |
return aContent.text |
|---|
| 141 |
elseif ValidFile( aContent, aName ) then |
|---|
| 142 |
local File = require( 'File' ) |
|---|
| 143 |
local HTTPFile = require( 'HTTPFile' ) |
|---|
| 144 |
local aDirectory = File( aContent.directory.path, 'file', '' ) |
|---|
| 145 |
local aHandler = HTTPFile( aDirectory.path ) |
|---|
| 146 |
|
|---|
| 147 |
return aHandler( aName ) |
|---|
| 148 |
end |
|---|
| 149 |
end |
|---|
| 150 |
end |
|---|
| 151 |
|
|---|
| 152 |
-------------------------------------------------------------------------------- |
|---|
| 153 |
-- DAV service methods |
|---|
| 154 |
-------------------------------------------------------------------------------- |
|---|
| 155 |
|
|---|
| 156 |
function self:options() |
|---|
| 157 |
HTTP.response.header[ 'allow' ] = 'DELETE, GET, HEAD, LOCK, MOVE, OPTIONS, PROPFIND, PUT, UNLOCK' |
|---|
| 158 |
HTTP.response.header[ 'content-type' ] = 'text/plain' |
|---|
| 159 |
|
|---|
| 160 |
return HTTP.response.header[ 'allow' ] |
|---|
| 161 |
end |
|---|
| 162 |
|
|---|
| 163 |
function self:propfind() |
|---|
| 164 |
local aContent = self.content |
|---|
| 165 |
|
|---|
| 166 |
if aContent and aContent.exists then |
|---|
| 167 |
local WikiDAV = require( 'WikiDAV' ) |
|---|
| 168 |
local aResource = DAVResource( aContent, self.name ) |
|---|
| 169 |
|
|---|
| 170 |
if aResource then |
|---|
| 171 |
return WikiDAV( aResource ):propfind() |
|---|
| 172 |
end |
|---|
| 173 |
end |
|---|
| 174 |
end |
|---|
| 175 |
|
|---|
| 176 |
-------------------------------------------------------------------------------- |
|---|
| 177 |
-- Metamethods |
|---|
| 178 |
-------------------------------------------------------------------------------- |
|---|
| 179 |
|
|---|
| 180 |
function meta:__call( aContent, aName ) |
|---|
| 181 |
local aService = { content = aContent, name = aName } |
|---|
| 182 |
|
|---|
| 183 |
setmetatable( aService, self ) |
|---|
| 184 |
|
|---|
| 185 |
return aService |
|---|
| 186 |
end |
|---|
| 187 |
|
|---|
| 188 |
function meta:__concat( aValue ) |
|---|
| 189 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 190 |
end |
|---|
| 191 |
|
|---|
| 192 |
function meta:__tostring() |
|---|
| 193 |
return ( '%s/%s' ):format( self._NAME, self._VERSION ) |
|---|
| 194 |
end |
|---|
| 195 |
|
|---|
| 196 |
function self:__index( aKey ) |
|---|
| 197 |
local aValue = getmetatable( self )[ aKey ] |
|---|
| 198 |
|
|---|
| 199 |
if not aValue and aKey:find( '^get.+' ) then |
|---|
| 200 |
local aName = aKey:match( '^get(.+)$' ) |
|---|
| 201 |
|
|---|
| 202 |
self.name = aName |
|---|
| 203 |
|
|---|
| 204 |
return function( self, anExtension ) |
|---|
| 205 |
|
|---|
| 206 |
self.name = ( '%s.%s' ):format( aName, anExtension or '' ) |
|---|
| 207 |
|
|---|
| 208 |
return self |
|---|
| 209 |
end |
|---|
| 210 |
elseif not aValue and aKey:find( '^propfind.+' ) then |
|---|
| 211 |
local aName = aKey:match( '^propfind(.+)$' ) |
|---|
| 212 |
|
|---|
| 213 |
self.name = aName |
|---|
| 214 |
|
|---|
| 215 |
return function( self, anExtension ) |
|---|
| 216 |
|
|---|
| 217 |
self.name = ( '%s.%s' ):format( aName, anExtension or '' ) |
|---|
| 218 |
|
|---|
| 219 |
return self |
|---|
| 220 |
end |
|---|
| 221 |
end |
|---|
| 222 |
|
|---|
| 223 |
self[ aKey ] = aValue |
|---|
| 224 |
|
|---|
| 225 |
return aValue |
|---|
| 226 |
end |
|---|
| 227 |
|
|---|
| 228 |
function self:__concat( aValue ) |
|---|
| 229 |
return tostring( self ) .. tostring( aValue ) |
|---|
| 230 |
end |
|---|
| 231 |
|
|---|
| 232 |
function self:__tostring() |
|---|
| 233 |
return tostring( self.name ) |
|---|
| 234 |
end |
|---|