Техзадание на CMS Stilllife 1.0

Назначение

Система предназначена для управления контентом широкого класа небольших веб-сайтов, начиная от так называемых«сайтов-визиток» и кончая ЖЖ-подобными блогами и форумами.

Т.е. всеми сайтами, основное содержимое которых генерируется людьми с помощью написания буковок в текстовом редакторе и загрузки картинок и видеофайлов.

Общей чертой данных сайтов является то, набор операций над любыми содержательными фрагментами контента сводится к "создать"/"отредактировать"/"переместить"/"удалить".

Поэтому нет необходимости для каждого сайта писать специфический код управляющий данными. Можно обойтись общим кодом.

Система расчитана на то, что cсылка на редко посещаемый небольшой сайт может быть внезапно опубликована на ресурсе, посещаемом миллионами людей, что вызовет всплеск посещаемости на несколько порядков.

Не предполагается что эта активность вызовет соответствующий всплеск активности по созданию/модификации контента.

В качестве основного средства ввода крупных фрагментов текста предполагается использование какого-нибудь WYSIWYG client-side редактора html, например fckeditor или tinymce, хотя предусматривается и возможность ввода информации в упрощенном формате (MarkDown, Textile), с последующим преобрзованием в xhtml на стороне сервера.

Хранение данных

Весь текстовый контент сайта хранится в виде HTML-файлов, готовых к отдаче пользователям. Редактирование вносит изменения непосредственно в эти файлы.

Поскольку информация об одном и том же содержательном объекте может существовать на сайте в нескольких местах (страница статьи, список статей в рубрике, лента обновлений), одна из копий считается главной. Именно её содержимое берется для редактирования.

Объект может быть представлен в файловой системе директорией, файлом или блоковым элементом xhtml в файле родительсокго объекта.

Объекты могут иметь скрытые атрибуты, не отдаваемые пользователям по http. Такие атрибуты хранятся в виде отдельных dbm-файлов, по файлу на атрибут, лежащих за пределами директории, раздаваемой веб-сервером как статический контент.

Существует интерфейс, позволяющий с правами администратора получить дамп всех скрытых атрибутов. Таким образом, если сайт онлайн, можно получить полный его бэкап, имея логин-пароль администратора для веб-интерфейса, даже если доступ к файловой системе сервера отсутствует.

Шаблоны страниц являются xhtml-файлами, валидными по соответствующией схеме W3C. Место, где в страницу вносятся содержательные данные объектов задается специальными именами классов.

Шаблоны могут располагаться как внутри доступного по http дерева сайта, так и вне его. В первом случае возможно их редактирование через web-интерфейс.

Описание имеющихся на данном сайте объектов, их отношений между собой и прочая необходимая для работы информация, находится в файле site.model, расположенном в корневой директории сайта. Файл site.model может быть защищен от неавторизованного доступа по http с помощью средств веб-сервера, это не нарушит работу системы.

Информация о правах доступа конкретных пользовалей к определенному поддереву сайта, находися в файле perms.txt, лежащем в корне этого поддерева.

Входящие в состав системы client-side скрипты обращаются к этому файлу, чтобы скрыть/показать интерфейсные элементы на странице в соответствии правами текущего пользователя, т.е. эти файлы должны быть доступны для скачивания всем, кому доступны сами страницы.

Обработка шаблонов

Подстановки в шаблонах

Подстановка в атрибуты HTML-элеметов

Как правило, содержимое объектов подставляется в шаблоны только вместо содержимого (innerHTML) xhtml-элементов. Если необходимо подставить значение атрибута в качестве атрибута xhtml-элемента (например, для формирования гиперссылки) то нужно описать возможность такой подстановки в site.model.

Вычислимые подстановки

Иногда недостаточно непосредственной подстановки атрибута, чтобы достичь требуемого эффекта, в то время как простые вычисления обеспечили бы получение нужных значений. Например, мы хотим чтобы каждый следующий уровень комментария был смещён на 20 пикселов левее предыдущего.

Хочется написать что-то вроде style="marginleft: 20*{level}px" Но наша модель шаблонов не позволяет размещать в шаблонах исполняемый на стороне сервера код.

Для таких простых вычислений предусмотены xml processing instructions. Инструкции sl:style и sl:class позволяют изменить атрибуты style и class у первого следующего за ними элемента html.

<?sl:style margin-left=20*level px ?gt;
<?sl:class +=list_no%2=0?"even":"odd" ?gt;

Инструкция sl:jsvar генерирует элемент script, cодержащий присваивание указаннй переменной значения, вычисленного на сервере.

<?sl:jsvar foo=level*20 ?>   

Сгенерирует

<script> var foo=60;</script> 

Если level имел значение 3.

Шаблоны страниц

Для основного представления страницы объекта используется шаблон с именем имя-типа.html. Имена шаблонов для альтернативных представлений страницы должны быть указаны явно в файле site.model при описании альтернативного представления.

Атрибуты заглавного объекта

В шаблоне страницы должен быть элемент с классом совпадающим с именем типа объекта. Как правило, все атрибуты объекта подставляются в элементы внутри этого класса. Исключение составляеют подстановки в элементы загловка (<head>). Поскольку объект считается заглавным, то есть владеющим данной страницей, то заголовок тоже принадлежит ему.

Списки объектов

Списки объектов состоят из блокового элемента с классом smth-list, внутри которого дизайнер должен предусмотреть три элемента - с классом smth (обязательно), smth-delimiter и smth-placeholder, где smth - имя типа объектов, отображаемых в данном списке. Кроме них могут быть любые другие элементы, формирующие верхний и нижний заглоовки.

Внутри элемента с классом smth должны быть предусмотрены элементы с классами, соответствующими атрибутам объекта (возможно не всем) и вычислимым атрибутам элемента списка. Если список является главным хранилищем объектов этого типа, то этому элементу будет приписан атрибут id.

Если список пуст, элементы smth-list и smth-delimiter получают style="display: none;" и не отображаются, а smth-placeholder, если он есть - отображается. Если его нет, то пустой список скрывается весь.

Если список содержит один элемент, то delimiter и placeholder скрвываются. Если список содержит более одного элемента, то элемент smth дублируется столько раз, сколько надо, и между каждыми двумя smth помещается копия smth-delimiter.

Шаблоны форм

Если для объекта не существует шаблона с именем editтип или createтип, система в состоянии сгенерировать форму создания/редактирования автоматически, пользуясь описанием атрибутов в файле site.model

Однако дизайнер сайта может создать шаблоны вручную или даже встроить формы создания/редактирования в другие страницы. Форма создания объекта должна иметь html-атрибут name равный имени типа создаваемого объекта.

Элементы управления

Элементы управления это ссылки или формы, размещенные на статических страницах и ведущие на скрипт, выполняющий какие-либо действия со страницей.

При обработке шаблона эти элементы находятся по наличию у них класса control и атрибут href у ссылки или action у формы заменяется на правильный путь к скрипту, в path_info которого указывается текущая страница. query_string остается неизменным, за исключением случая, когда элемент управления относится к объекту, которых на странице целый список. Тогда в query_string добавляется id=идентификатор объекта.

Стандартный клиент-сайд скрипт при загрузке страницы проходит по этим элементам и, в зависимости от прав текущего пользователя на страницу, либо скрывает их, либо открывает, ориентируясь на наличие параметра равного имени действия в query_string или атрибута name у кнопки submit.

На усмотрение дизайнера оставляется, будут эти элементы видимы или скрыты, если у пользователя отключен javascript.

Если элемены по умолчанию видимы, то появляется возможность работать с сайтом в браузере с отключенным javascript, но при этом у большинства пользователей будут при загрузке страницы некрасиво мигать элементы, доступные только администратору.

Возможные значения действий create (должна сопровождаться параметром с именем type), edit, move, delete, chaccess.

Общий декор сайта

Cпециальный шаблон decor.html может содержать общее для всего сайта оформление. Внутри него должен быть расположен блоковый элемент с классом pagebody. Если такой элемент существует, то при изменении шаблона страницы, для которой в site.model не запрещено использование декора, проверяется, есть ли в нем элемент с таким классом. Если он есть, то всё содержимое html вокруг него заменяется на соответствующие части шаблона decor. Если его нет, то считается что <div class="pagebody"> вложен непосредственно в <body>.

В шаблоне decor могут использоваться списки. Например, это позволяет сформировать общее для всех страниц сайта меню, или какое-нибудь облако тэгов. Поскольку любые списки должны быть отражены в модели, decor рассматривается как альтернативное представление объекта site.

Особенности создания/редактирования объектов

Автосоздание объектов

Существуют объекты, которые не обязательно создавать явно. Например тэги в блоге. При создании записи в блоге пользователь заполняет поле тэгов, и если тегов с указанными именами нет, они автоматически создаются.

Такие объекты, создающиеся вместе с другим объектом, должны иметь только атрибут name.

Другим видом автосоздаваемого объекта является объект пользователь. При первом логине пользователя по OpenID автоматически создается объект пользователь, со всеми атрибутами, которые сообщит OpenID-сервер.

Обработка картинок

Картинки могут быть приаттачены к любому редактируемому/создаваемому объекту. Если хранилище объекта является директорией, то картинка сохраняется прямо с тем именем, с которым она загружена на сайт. Если хранилище объекта является файлом или блоком в файле объемлющего объекта, то к имени файла дописывается префикс сделанный имени объекта, таким образом, чтобы во все объекты могли быть загружены картинки с одинаковым именем и не породить конфликта.

Если в момент загрузки картинки в загружаемом одновременно тексте обнаружена ссылка на локальный файл с именем картинки, она переписывается так, чтобы правильно указывать на картинку.

Редактирование шаблонов

При сохранении существующего шаблона страницы через web-интерфейс он начинает применяться ко всем существующим страницам данного типа.

Пользовательские сессии

При логине пользователя (локальном или через OpenID) ему выдаются две куки. Одна кука представляет собой псевдослучайный набор шестнадцатиричных цифр и является ключом хранящегося на сервере хэша сессий. По этой куке пользователь авторизуется серверными скриптами.

Вторая представляет собой никак не защищенное имя пользователя. Она используется client-side скриптами для скрытия/показа элементов управления.

Кроме этого, можно экспортировать в куки некоторые атрибуты пользователя, для того чтобы ими могли воспользоваться client-side скрипты.

Синтаксис site.model

Блоки описывающие объект

Блоки, описывающие объект бывают четырех видов site, dir, file и block. Они имеют вид

site hostname { }

dir тип-объекта { }

file тип-объекта { }

block тип-объекта { }

Для всех объектов кроме сайта нужно указыать предложение part of, содержащее список типов объектов, частью которых может быть данный объект.

Например:

file article { part of topic; ... }

dir topic { part of topic, site; ... }

Объекты с хранилищем file и dir могут быть только частью объекта с типом хранилища dir (в том числе сайта, у которого этот тип хранилища неявно подразумевается). Объект типа block может быть частью как file, так и dir. Вложенные block недопустимы.

Внутри блока описания объекта должны присутствовать:

  1. Способ формирования его уникального идентификатора - имени файла/директории или id блока (кроме объекта site).
  2. Список описаний атрибутов хранимых атрибутов этого объекта

В описании объекта могут присутствовать:

  1. Описания вычислимых атрибутов
  2. Описания альтернативных представлений объекта
  3. Описание ограничений на создание/редактирование объектов.
  4. Директива no decor, указывающая что данная страница не должна иметь стандартого для всех страниц сайта оформления.

Имя объекта и URL

У всех объектов с хранилищем dir и file есть атрибут filename, который указывает имя файла. У объектов с хранилищем block есть атрибут id.

У всех объектов также есть атрибут date, задающий дату создания.

Этот атрибут может быть сформирован автоматически, исходят из других атрибутов.

Например:

 filename  name%translit + ".html";
 filename date%"%y/%m/%d-"+name+".html";
 filename "tag/"+name + ".html";

Знак % означает команду форматирования. Для строк предусмотрены следующие виды форматирворваия translit, *uriescape, entityescape,(число). для даты поддерживаются все форматы strftime.

Если сформированное в момент создания объекта имя содержит слэши, то при сохранении объекта будет при необходимости создано несколько уровней директорий.

Если filename не начинается со слэша, оно интерпретируется относительно объекта, частью которого является создаваеый объект.

У блоков вместо filename используется id.

id name%translit;

В качестве специального значения можно использовать конструкцию sequence();

id "a"+sequence()%"%05d";

Атрибуты

Для атрибута необходимо специфицировать тип, место хранения (класс html-элемента или hidden, тогда атрибут будет храниться в dbm за пределами html-дерева). Необходимо позаботитья о том, чтобы в шаблоне страницы присутствовали элементы-хранилища для всех атрибутов, которые не описаны как hidden.

Типы бывают block (местом хранения может быть только блоковый html-элемент, разрешена любая разметка), inline (местом хранения может быть inline-html-элемент, span или a, допустима только разметка, допустимая в данном месте), string (никакая разметка недопустима) ascii (допустимы только ascii символы), ident (допустимы латинские буквы цифры, дефис, точка и подчерк, начинается с буквы) number и date.

Кроме этого можно указать дополнительные места в html, куда подставляется данный атрибут.

Синтаксис указания места в html отдаленно напоминает css-селекторы. То есть допустимы конструкции элемент, элемент.класс, .класс. В качестве дополнительной возможности можно указать элемент.класс.атрибут

Так же у атрибута могут быть указаны ограничения на его редактирование. Например, можно запретить пользователю редактировать атрибут status в объекте, представляющем его самого, и разрешить редактирование статусов пользователей только модератору.

Может быть указано что атрибут указывает на другой объект.

attribute name {
    type string;
    store title; 
    display h1.title;
}

attribte status {
    type enum ("novice","user","native","moderator");
    store .status;
    restrict edit,create moderators;
    default "novice";
}

attribute tag {
    type list of strings;
    store .list-tag a.tag;
    display .list-tag a.tag.href;
    links to tag autocreate;
}

Если атрибут указывает на объект, то в качестве альтернативного представления можно использовать блок, содержащий атрибуты данного объекта. В момент обработки этого блока в шаблоне, текущим объектом будет тот, на который указвает атрибут-ссылка.

Например:

attribute author {
    type string;
    store span.author;
    restrict edit,create anybody;
    default currentuser();
    links to author;
    display div.author embed;
}

Вычислимые атрибуты

Описываются аналогично обычным атрибутам, только вместо предложения store имеют предложение value, содержащее формулу рассчета по значениям других атрибутов. Кроме предложения value описание вычислимого атрибута может содержать только предложение display.

Cписки в site.model

Если на странице объекта встраивается список каких-то других объектов, то критерий отбора этого объекта должен быть описан в описании соответствующего объекта.

list of тип-объекта шаблон-поиска [лимит] порядок

Если этот список является основным местом хранения данного объекта, то в качестве шаблона поиска указывается stored here, в остальных случаях это шаблон имени файла относительно страницы объекта.

Лимит задает количество записей на одной странице. В случае stored-here он вызывает создание дополнительных страниц (например длинная дискуссия в форуме). В остальных случаях если объектов, достойных включения в список больше лимита, остальные объекты игнорируются. Лимит можно указать как nm, например 205, в этом случае будут созданы n страниц по m элементов. Если m не указано, например 50*, будет создано столько страниц, сколько надо, чтобы вестить все объекты.

Порядок элементов для списков собираемых по файловой системе задается примерно как в sql:

order date asc, name desc

Для элементов списка stored here, порядок может быть new at start, new at end или tree-style.

Альтернативные представления страницы

Иногда бывают случаи, что один и тот же объект нужно уметь представить по нескольким шаблонам. Для этого используется блок alternate, содержащийся внутри блока соотвествующего объекта.

Имя альтернативного представления, указанное между словом alternate и открывающей фигурной скобкой, используется в качестве имени шаблона для рендеринга.

Внутри alternate должно присутствовать приложение filename. Кроме того допустимы конструкции list of, описания вычислимых атрибутов и директива no decor.

Если альтернативное представление страницы имеет XML-схему, отличную от XHTML (rdf, rss, atom, foaf), то нужно указать предложение content-type тип-медиа. Использование content-type, отличного от text/html автоматически предполагает no decor.

Например

alternate rssfeed { filename name + ".rss"; content-type application/rss+xml; attribute title { value "Новости сайта "+name; display title; } list of news 50 order date desc; }

Кроме того, альтернативный вид может быть описан как продолжение (использоваться для 2 и последующих страниц списка, разбитого на страницы).

Для этого в описание списка следует включить предолжение

continuation [of другое-альтернативное-представление];

Специальный случай альтернативного представления сайта, это общие для всех страниц сайта меню, включаемые в шаблон decor. decor рассматривается как альтернативно представление сайта (корневой страницы). Представлению decor не нужно иметь filename.

Описания ограничений на редактирование

Ограничения на редактирования описываются предложением restrict.

restrict операция роль[,роль]

Где операция может быть create,edit,move,delete,chaccess. Роль может быть owner,localuser,user или имя группы, описанной в файле perms.txt в директории объекта или выше по иерархии вплоть до корня сайта.

Cуществуте предопределнная роль banned, членам которой запрещены все действия, независимо от того, являются ли они локальными юзерами или нелокальными.

Использование роли owner имеет смысл только если у объекта есть атрибут author.

Предопределенный объект page

Если объект содержит список, допускающий разбиение на страницы (stored here + лимит или лимит вида m*n), то в шаблон страницы можно включить список page-list. У объекта page имеются атрибуты number url и current (последний принимает значения 0 и 1 в зависимости от того, является ли данная страница текущей) которые имеют соответствено спецификации;

attribute number { type number; display .number; }

attribute url { type string; display a.number.href }

To Be done

  1. И всё-таки кроме стандартных действий create/edit/move/delete нужно предусмотреть какие-то ещё дополнительные возможности.

    Напрашивается следующий интерфейс плагинов - результат сабмита пользователем формы (форму пусть в html рисуют) передают на вход чему-то исполняемому. Можно прям как есть в виде multipart/form-data или application/x-www-form-urlendocded. Можно - преобразовав для начала в какой-нибудь более-менее разумный xml.

    Плагин выполняет необходимую обработку результатов формы и вываливает нам обратно результат сабмита одной или нескольких форм том же самом виде. То есть такой препроцессор для стандартных операций edit/create/delete.

    Если общаться с плагинами через XML, то можно разрешить плагины на xslt писать.

  2. Ещё хочется что-то типа вычислимых атрибутов уровня сабмита. Чтобы с одной стороны можно было прямо в site.model можно было реализовать простейшие обработчики форм, например опрос, а с другой был бы гибкий метод прописывания всяких счетчиков вроде 20 статей в этой рубрике, последняя тогда-то.

  3. Не описано так же каким образом осуществляется подписка на обновления по электронной почте.

  4. И идею древовидных списков стоило бы расписать поподробнее.