-------------------------------------------------------------------------------- -- 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