--------------------------------------------------------------------------------
-- Title: WikiRecentService.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 NaturalComparator = require( 'NaturalComparator' )
local Template = require( 'Template' )
local URL = require( 'URL' )
local WikiContent = require( 'WikiContent' )
local WikiContentService = require( 'WikiContentService' )
local WikiDateService = require( 'WikiDateService' )
local WikiRecent = require( 'WikiRecent' )
local WikiService = require( 'WikiService' )
local BaseLink = WikiService.BaseLink
local DateLink = WikiService.DateLink
local FeedLink = WikiService.FeedLink
local IndexLink = WikiService.IndexLink
local ContentIterator = WikiService.ContentIterator
local Description = WikiService.Description
local Encode = WikiService.Encode
local FormatDate = WikiService.FormatDate
local FormatTime = WikiService.FormatTime
local GetType = WikiService.GetType
local HTML = WikiService.HTML
local Path = WikiService.Path
local Today = WikiService.Today
local Yesterday = WikiService.Yesterday
local ThisWeek = WikiService.ThisWeek
local Tag = WikiService.Tag
local os = require( 'os' )
local table = require( 'table' )
local getmetatable = getmetatable
local ipairs = ipairs
local pairs = pairs
local setmetatable = setmetatable
local require = require
local tostring = tostring
--------------------------------------------------------------------------------
-- WikiRecentService
--------------------------------------------------------------------------------
module( 'WikiRecentService' )
_VERSION = '1.0'
local self = setmetatable( _M, {} )
local meta = getmetatable( self )
--------------------------------------------------------------------------------
-- Utilities
--------------------------------------------------------------------------------
local function ContentComparator( aContent, anotherContent )
return NaturalComparator()( aContent.title, anotherContent.title )
end
local function EntryComparator( anEntry, anotherEntry )
local aTime = anEntry.time
local anotherTime = anotherEntry.time
return aTime > anotherTime
end
local function Entries()
local aMap = {}
local aList = {}
for aName in WikiRecent[ '' ] do
local aContent = WikiContent( aName )
local aModification = aContent.modification
local aDate = os.date( '!*t', aModification )
local aTime = os.time( { year = aDate.year, month = aDate.month, day = aDate.day } )
local someItems = aMap[ aTime ]
if not someItems then
someItems = {}
aMap[ aTime ] = someItems
end
someItems[ #someItems + 1 ] = aContent
end
for aTime, someItems in pairs( aMap ) do
table.sort( someItems, ContentComparator )
aList[ #aList + 1 ] = { time = aTime, items = someItems }
end
table.sort( aList, EntryComparator )
return aList
end
local function TimeTitle( aTime )
local aTitle = FormatDate( aTime )
if Today( aTime ) then
aTitle = ( 'Today — %s' ):format( aTitle )
elseif Yesterday( aTime ) then
aTitle = ( 'Yesterday — %s' ):format( aTitle )
elseif ThisWeek( aTime ) then
aTitle = ( 'Few days ago — %s' ):format( aTitle )
end
return aTitle
end
--------------------------------------------------------------------------------
-- DAV Utitities
--------------------------------------------------------------------------------
local function DAVIterator()
local anIterator = WikiRecent[ '' ]
return function()
local aName = anIterator()
if aName then
local aContent = WikiContent( aName )
local aModification = aContent.modification
local aResource = { name = aName, mode = 'directory', modification = aModification, size = 0 }
return aResource
end
end
end
local function DAVResource()
local anIterator = DAVIterator()
local aModification = WikiRecent[ 'modification' ]
local aResource = { iterator = anIterator, mode = 'directory', modification = aModification, size = 0 }
return aResource
end
--------------------------------------------------------------------------------
-- Service methods
--------------------------------------------------------------------------------
self.toURL =function( aService, anObject )
return URL( aService.prefix )
end
self.toObject = function( aService, aURL )
local WikiRecentService = require( 'WikiRecentService' )
local aService = WikiRecentService()
return aService
end
function self:getHtml()
local aLayoutTemplate = Template[ 'WikiLayout.txt' ]
local aTemplate = Template[ 'WikiRecentService.txt' ]
local anEntryTemplate = aTemplate[ 'entries' ]
local aCount = 0
aTemplate[ 'title' ] = 'Recent'
aTemplate[ 'entries' ] = nil
for _, anEntry in ipairs( Entries() ) do
local anEntryTemplate = aTemplate[ 'entries' ]
local aTime = anEntry.time
local aDate = os.date( '!*t', aTime )
local aService = WikiDateService( aDate.year, aDate.month, aDate.day )
local aURL = HTTPService[ aService ]
anEntryTemplate[ 'description' ] = Encode( Description( #anEntry.items ) )
anEntryTemplate[ 'title' ] = TimeTitle( aTime )
for _, aContent in ipairs( anEntry.items ) do
local anItemTemplate = anEntryTemplate[ 'items' ]
local aService = WikiContentService( aContent )
local aURL = HTTPService[ aService ]
anItemTemplate[ 'link' ] = Encode( aURL.path )
anItemTemplate[ 'modification' ] = Encode( FormatTime( aContent.modification ) )
anItemTemplate[ 'by' ] = WikiService.By( aContent, true )
anItemTemplate[ 'title' ] = Encode( aContent.title )
anItemTemplate[ 'tag' ] = Tag( aContent.modification, true )
aCount = aCount + 1
anEntryTemplate[ 'items' ] = anItemTemplate
end
aTemplate[ 'entries' ] = anEntryTemplate
end
aTemplate[ 'description' ] = Encode( Description( aCount ) )
aLayoutTemplate[ 'baseLink' ] = Encode( BaseLink() )
aLayoutTemplate[ 'indexLink' ] = Encode( IndexLink() )
aLayoutTemplate[ 'dateLink' ] = Encode( DateLink() )
aLayoutTemplate[ 'feedLink' ] = FeedLink( self, aCount )
aLayoutTemplate[ 'path' ] = Path( self )
aLayoutTemplate[ 'query' ] = nil
aLayoutTemplate[ 'robot' ] = 'noindex'
aLayoutTemplate[ 'title' ] = 'Recent'
aLayoutTemplate[ 'content' ] = aTemplate
return tostring( aLayoutTemplate )
end
function self:getXml()
local WikiFeed = require( 'WikiFeed' )
local WikiIndex = require( 'WikiIndex' )
local anIterator = ContentIterator( WikiRecent[ '' ] )
local aGenerator = HTML
local aTitle = 'Recent'
local aContext = { title = aTitle, link = HTTP.request.url, creation = WikiIndex[ 'creation' ] }
HTTP.response.header[ 'content-type' ] = 'application/atom+xml; charset=utf-8'
return tostring( WikiFeed( anIterator, aGenerator, aContext ) )
end
function self:get( aType )
return GetType( self, aType )
end
--------------------------------------------------------------------------------
-- DAV service methods
--------------------------------------------------------------------------------
function self:options()
HTTP.response.header[ 'allow' ] = 'GET, HEAD, OPTIONS, PROPFIND'
HTTP.response.header[ 'content-type' ] = 'text/plain'
return HTTP.response.header[ 'allow' ]
end
function self:propfind()
local WikiDAV = require( 'WikiDAV' )
local aResource = DAVResource()
return WikiDAV( aResource ):propfind()
end
--------------------------------------------------------------------------------
-- Metamethods
--------------------------------------------------------------------------------
function meta:__call()
local aService = {}
setmetatable( aService, self )
return aService
end
function meta:__concat( aValue )
return tostring( self ) .. tostring( aValue )
end
function meta:__tostring()
return ( '%s/%s' ):format( self._NAME, self._VERSION )
end
function self:__index( aKey )
local aValue = getmetatable( self )[ aKey ]
if not aValue and aKey:find( '^get.+' ) then
local aName = aKey:match( '^get(.+)$' )
local aContent = WikiContent( aName )
if aContent and aContent.exists then
local aService = WikiContentService( aContent )
return function()
return aService
end
end
end
self[ aKey ] = aValue
return aValue
end
function self:__concat( aValue )
return tostring( self ) .. tostring( aValue )
end
function self:__tostring()
return 'Recent'
end