Авторизуйтесь или зарегистрируйтесь, чтобы создать новую тему

Программизм. Серия 3

trophim
70
trophim 15.11.2010 02:53 | #

У меня тут тележка вопросов образовалась...

1. Каким образом узнать входит ли юзер с ID=N в некоторую группу с ID=M. Точнее задача такова: есть список ID (например, такой: 1006, 1007, 1008) и получив на входе идентификатор N текущего пользователя узнать, а входит ли он в этот список напрямую (ну, это просто на равенство сравнить) или в группу, если таковая есть в вышеуказанном списке.

 

2. Каким образом обеспечить возможность работы с аттачментами? Каким образом обеспечить обработку вставки картинок (контрол rte допускает их ставку). Что необходимо обеспечить в своем модуле, чтобы работало добавление аттачей и картинок. Это несколько разные задачи или они схожи по реализации? 

 

3. Что необходимо делать для поддержки поиска (при помощи встроенного поиска)? Я так понимаю что для того, чтобы работал поиск по тексту, то везде где модуль использует текст, его необходимо 'скормить' внутреннему индексатору.

 

4. А каким образом осуществляется выполнение фильтрации (как в модуле Задания, там значок такой в виде воронки)? Это делается через встроенные возможности поиска или просто поиском подстроки?

Что делает эта конструкция: 

if (!TeamWox.isMobile)
pageheader.Filter( "/tasks/all", "<tw:keyword />" );
  

5. Каков логический смысл действия 'Отложить' для заданий? Меняется статус задания (я так понял есть всего три состояния: открыто/завершено/закрыто или для событий есть еще дополнительное 'отложено')? Каков смысл команды 'Закрыть' для событий?

 

6. Что есть такое snippet? 

TeamWox.Control("Input", "rte", ......
.Append("onsnippetcreate",CreateSnippet)
.Append("onsnippetinsert",InsertSnippet)

 

7. Что за интерфейсы запрашивает у модуля сервер??? И что дает реализация каждого из них (а то может и нужен он вовсе)
IUserProfilePage
IToolbar
IModuleTips
IWidgets
ITeamPage
IProvidersManager
IClientDepend
IProductDepend
ISocialRelationsClient
IModuleStatistics
 

Вот как-то так. 8-) 

TeamWox SDK: Поиск и фильтрация - Часть 2

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

pvoid
132
pvoid 15.11.2010 13:17 | #
6. Что есть такое snippet? 

TeamWox.Control("Input", "rte", ......
.Append("onsnippetcreate",CreateSnippet)
.Append("onsnippetinsert",InsertSnippet)

Это встроенный механизм работы с шаблонами. Подробнее они описаны в справке Шаблоны.

Любой модуль может добавить в этот шаблон необходимые ему данные, например задания добавляют назначенных, важность, приватность и т.д. Для этих целей и служат события. Событие "onsnippetcreate" говорит о том что создается новый шаблон. параметром в это событие передается объект, свойства которого будут сохранены.

"onsnippetinsert" генерируется при вставке шаблона, параметром также передается объект содержащий ранее сохраненные свойства.

Для того что бы этот механизм заработал в rte необходимо указать параметрами идентификатор модуля

var rte = TeamWox.Control('Input','rte','name','<b>text!</b>',{upload:'/module/upload/',moduleId:24});

 

alexey
487
alexey 15.11.2010 15:05 | #

trophim:

1. Каким образом узнать входит ли юзер с ID=N в некоторую группу с ID=M. Точнее задача такова: есть список ID (например, такой: 1006, 1007, 1008) и получив на входе идентификатор N текущего пользователя узнать, а входит ли он в этот список напрямую (ну, это просто на равенство сравнить) или в группу, если таковая есть в вышеуказанном списке.

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

  • int GroupsCount() - количество групп, в которые входит пользователь;
  • INT64* Groups() - массив идентификаторов групп.

В контексте запроса (Context) список групп для текущего пользователя (context->user) уже доступен для запроса и использования.

В случае, если Вы запрашиваете информацию о пользователе через интерфейс IUserManager, то при запросе Вам необходимо указать флаг USER_INFO_USERS_GROUPS.

Например:

CSmartInterface<IUser> user;
if(RES_FAILED(res=m_user_manager->UserGet(NULL, user_id, USER_INFO_USERS_GROUPS, &user)) || user==NULL)
   return(res);
//--- ищем группу
const INT64* groups =user->Groups();
bool         founded=false; 
for(int i=0, count=user->GroupsCount(); i<count; i++)
  {
   //--- сравниваем id группы
   if(groups[i]==group_id)
     {
      founded=true;
      break;
     }
  }
trophim
70
trophim 15.11.2010 21:47 | #
Спасибо за ответы. Что насчет остальных вопросов?
trophim
70
trophim 17.11.2010 01:33 | #
Остальное не поддается отвечанию? :-(
alexey
487
alexey 17.11.2010 12:58 | #
trophim:
Остальное не поддается отвечанию? :-(

Приносим свои извинения за задержку. В ближайшее время Вы получите ответ на остальные вопросы.

trophim
70
trophim 22.11.2010 00:42 | #
Уж полночь близится, а ансверов все нет...
pvoid
132
pvoid 22.11.2010 12:21 | #

Приносим прощения за долги ответ. Разработчики были заняты подготовкой нового релиза 

2.Каким образом обеспечить обработку вставки картинок (контрол rte допускает их ставку). Что необходимо обеспечить в своем модуле, чтобы работало добавление аттачей и картинок.

Возможность вставка изображений в редактируемый текст происходит в два этапа. На первом, во время набора текста картинки загружаются на сервер и сохраняются как временные файлы. Для этого вам понадобится реализовать обработку таких загружаемых файлов. Допустим мы будем принимать ихпо адресу "/testmodule/upload/".

Тогда при создании редактора вам необходимо указать этот адрес

TeamWox.Control("Input","rte","content","",{upload:"/testmodule/upload"}).Style("height","300px");

Далее в методе ProcessPage вашего модуля необходимо обработать приходящие с клиента файлы

if(PathCompare(L"upload",path))
  {
   IRichTextEdit *rte=NULL;
   //--- получим интерфейс упрощающий работу с редактором
   if(RES_SUCCEEDED(res=m_server->GetInterface(L"IRichTextEdit",(void **)&rte)) && rte!=NULL)
     {
      //--- сохраним пришедший файл как временный и сделаем его доступным по адресу /testmodule/image/ + id файла
      res=rte->Upload(context, L"/testmodule/image/");
      rte->Release();
      return(res);
     }
   //---
   ReturnError(res);
  }

Далее для того что бы файл отображался во время редактирования и после записи текста, вам необходимо реализовать возврат этого файла по адресу /testmodule/image/. Для этого все в том же ProcessPage реализуем обработку этого адреса

if(PathCompare(L"image",path))
  {
   // конечно делать прямо так в рабочем проекте нельзя, необходимы проверки корректности
   // которые в данном случае убраны для простоты примера.
   // задача кода получить идентификатор файла из пути вид /testmodule/image/122 где 122 искомый id
   INT64 id = _wtoi64(path+6);
   // в зависимости от вашей задачи, здесь может быть проверка прав доступа пользователя к этому файлу.
   // получим файловый менеджер
   IFilesManager*  files_mngr=NULL;
   if(RES_FAILED(server->GetInterface(L"IFilesManager", (void**)&files_mngr)))
      ReturnError(RES_E_FAIL);
   // скажем файловому менеджеру отправить файл кэшируемым и inline объектом (без заголовка Content-Disposition:attachment)
   return(files_mngr->FileSend(context,download_id,IFilesManager::SEND_MODE_CACHE | IFilesManager::SEND_MODE_INLINE));
  }

Теперь вам необходимо при записи содержимого набранного в редакторе перевести файлы из временных в постоянные. Делается это момоходом, при обработке присланного текста IHtmlCleaner для удаления мусора и прочих не разрешенных html тэгов и аттрибутов. В следующем примере мы получаем данные присланные редактором с именем content, созданным нами в примере кода на JavaScript

CSmartInterface<IHtmlCleaner> cleaner;
const wchar_t *cleaned=NULL;
// получим присланное содердимое редактора
content    =(wchar_t*)context->request->GetString(IRequest::POST,L"content");
content_len=0;
// получим у сервера интерфейс IHtmlCleaner
if(RES_FAILED(server->GetInterface(L"IHtmlCleaner",(void**)&cleaner)) || cleaner==NULL)
  {
   ExtLogger.Out(context,LOG_STATUS_ERROR,"Update: failed create cleaner");
   //---
   return(RES_E_FAIL);
  }
//--- укажем URL на котором подсчитываем картинки
cleaner->SetImageUrl(L"/board/image/");
//--- запускаем обработку через чистильщик
if(RES_FAILED(res=cleaner->Process(context,L"PostRule",content)) || (cleaned=cleaner->GetBuffer(NULL))==NULL)
  {
   ReturnErrorExt(res,context,"failed body clean");
  }
//---
if(cleaned!=NULL && StringCchLength(cleaned,STRSAFE_MAX_CCH,&content_len)==S_OK)
  {
   // здесь необходимо сохранить полученный текст туда где вы его будете хранить. Мы настоятельно рекомендуем
   // использовать для этих целей файловое хранилище. Подробнее все это можно увидеть в модуле Board в SDK
  }
На живом примере все это можно увидеть и проследить под отладчиком на примере модуля Board из TeamWox SDK

 

AgentRX
201
AgentRX 22.11.2010 16:23 | #
trophim:

У меня тут тележка вопросов образовалась...

2. Каким образом обеспечить возможность работы с аттачментами? Каким образом обеспечить обработку вставки картинок (контрол rte допускает их ставку). Что необходимо обеспечить в своем модуле, чтобы работало добавление аттачей и картинок. Это несколько разные задачи или они схожи по реализации? 

Объясню на примере модуля Board, входящего в состав SDK.

Шаблонная часть

Создание контрола Attachments внутри edit.tpl:

...
attaches = TeamWox.Control("Attachments",
                           "attachments",
                           [<tw:attachments />],
                           "/board/download/",
                           top.TeamWox.ATTACHMETS_ALL,
                           "/board/attachments/upload");
...

Параметры контрола (начинаются со 2го параметра в функции TeamWox.Control. Первый параметр - название) :

{String} name
Имя POST переменных с добавленными файлами.
{Array} files
Уже прикрепленные файлы. Каждый элемент массива описывает файл.
{
  "id":"411",           // Идентификатор файла в TeamWox
  "name":"photo.jpg",   // Имя файла
  "mime":"image/jpeg",  // MIME тип файла
  "size":407286,        // Размер файла в байтах
  "type":1              // Внутренний тип файла, для встроенного просмотрщика
}
Лучше всего выводить эти данные при помощи метода IAttachments::WriteList, 
который по имеющимся файлам построит массив нужного вида.
{String} link
Cсылка по которой (с указанием ID) происходит получение файла
{Number} flags Optional
Задает встроенные объекты? которые можно добавить к прикрепленным файлам. Возможные значения: 
top.TeamWox.ATTACHMETS_OBJECTS, 
top.TeamWox.ATTACHMETS_MINDMAP, 
top.TeamWox.ATTACHMETS_CHARTS, 
top.TeamWox.ATTACHMETS_DIAGRAM, 
top.TeamWox.ATTACHMETS_ALL
{String} uploadLink Optional
Ссылка для загрузки файлов на сервер. Необходима только при добавлении объектов через Flash редактор.

 

C++ часть

Файл PageEdit.cpp. Функция Tag. По определенному тэгу выводим список аттачей: 

//+------------------------------------------------------------------+
//| Обработка тэга                                                   |
//+------------------------------------------------------------------+
bool CPageEdit::Tag(const Context *context,const TagInfo *tag)
  {
...
//--- ПРИКРЕПЛЕННЫЕ ФАЙЛЫ
   if(TagCompare(L"attachments",tag))
     {
      IAttachments *attachments;
      if(RES_FAILED(m_server->GetInterface(TWX_SERVER,L"IAttachments",(void **)&attachments))) return(false);
      attachments->WriteList(context,m_server,m_message->GetAttachments(),m_message->GetAttachmentsCount());
      //---
      return(false);
     }
...

 

Файл PageEdit.cpp. Функция OnUpdate. Идет получение удаленных и новых приложенных файлов. Также идет получение файлов, вставленных из других модулей (в нашем случае - это Документы):

//+------------------------------------------------------------------+
//| Обработка action'а на обновления                                 |
//+------------------------------------------------------------------+
TWRESULT CPageEdit::OnUpdate(const Context *context,const wchar_t *path,IBoards *i_manager)
  {
...
//--- УДАЛЕННЫЕ ФАЙЛЫ
   if(context->request->Exist(IRequest::POST,L"attachments_deleted") && 
     (id_str=context->request->GetString(IRequest::POST,L"attachments_deleted"))!=NULL)
     {
      //--- очистим
      ZeroMemory(id_list,sizeof(id_list));
      id_count=_countof(id_list);
      //--- распарсим строку и сохраним удаляемые файлы
      if(StringParse(id_str,id_list,&id_count)==RES_S_OK && id_count>0)
        {
         for(int i=0;i<id_count;i++)
            message->DelAttachments(id_list[i]);
        }
     }
//--- НОВЫЕ ФАЙЛЫ
   context->request->PrepareIterator(&it);
   while(context->request->GetFile(L"attachments",NULL,&file_desc,&it))
     {
      message->AddAttachments(&file_desc);
     }
//--- получим интерфейс для обработки вставки из модулей
   CSmartInterface <IAttachmentsFiles> attach_files;
//---
   if(RES_SUCCEEDED(server->GetInterface(L"IAttachmentsFiles",(void**)&attach_files)) && attach_files!=NULL)
     {
      CBoardMessage *message_obj=(CBoardMessage*)message;
      if(RES_SUCCEEDED(attach_files->Init(context)))
        {
         for(int tt=0,count=attach_files->Count(); tt<count; tt++)
           {
            INT64 id=attach_files->FileId(context, tt);
            if(id>0) message_obj->AddAttachments(id);
           }
        }
      //--- освободим интерфейс
      attach_files=NULL;
     }
...

 Для более подробной информации смотрите реализацию механизма в модуле Board из SDK.

trophim
70
trophim 23.11.2010 16:22 | #

Большое спасибо, завтра буду пробовать И, соответственно, писать благодарности... или гневные отзывы :-). 

P.S. Кстати, почему вы не используете CSmartInterface везде, где это необходимо? Или это зависит от стиля конкретного разработчика? 

К списку тем  | 12

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий