unit Users;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ComCtrls, ExtCtrls, ActnList;

const
  PREVILEG_ZAPUSK_MASHIN_1 = 1;
  PREVILEG_ZAPUSK_MASHIN_2 = 2;
  PREVILEG_ZAPUSK_MARSH = 3;
  PREVILEG_SET_PARAMETERS = 4;
  PREVILEG_CHANNELS = 5;
  PREVILEG_ADMIN = 6;
  PREVILEG_USERS = 7;
  PREVILEG_PROD_USER = 8;
  PREVILEG_PROD_ADMIN = 9;
  PREVILEG_DEL_MESSAGES = 10;
  PREVILEG_DB_BACKUP = 11;
  PREVILEG_MSQ_EDIT = 12;
  PREVILEG_MSQ_SM_EDIT = 13;
  PREVILEG_NOTES_EDIT = 14;
  PREVILEG_PRM_SPEC1 = 15;
  PREVILEG_SEQC_EDIT1 = 16;
  PREVILEG_SEQC_EDIT2 = 17;
  PREVILEG_BLOK = 18;
  PREVILEG_MCHMODE = 19;
  PREVILEG_ZAPRET_MES = 20;

  PREVILEG_ZAPRET_ARHIV = 21;
  PREVILEG_ZAPRET_GRAFIKOV = 22;


  PREVILEG_ZAPRET_CHECKBOX = 23;
  PREVILEG_ZAPRET_RADIOBOX = 24;
  PREVILEG_ZAPRET_BUTTON = 25;
  PREVILEG_ZAPRET_COMBOBOX = 26;
  PREVILEG_ZAPRET_TRACKBAR = 27;


  USER_SUPERVISOR = 1;

const
  prvlg: array [1..24] of string =(
    '1; Запуск машин (категория 1); *** зарезервировано ***',
    '2; Запуск машин (категория 2); *** зарезервировано ***',
    '3; Запуск/останов маршрутов; Разрешение на запуск и останов маршрутов',
    '4; Изменение параметров датчиков; Настройка порогов срабатывания датчиков, задержек и др. параметров',
    '5; Установка каналов; Разрешение на изменение адресов машин и датчиков',
    '6; Админ: Вход; Разрешение на вход в режим администрирования',
    '8; Учет продукта (оператор); Разрешение на изменение информации о хранении продукта',
    '9; Учет продукта (админ); Разрешение на изменение таблиц типов продукта и поставщиков',
    '12; Цепочки: Редактирование; Разрешение на редактирование цепочек',
    '13; Цепочки: Шаблоны; Разрешение на редактирование шаблонов цепочек',
    '14; Комментарии; Разрешение на добавление / изменение комментариев к на панелях управления устройств',
    '15; Установка параметров (специальная - 1)',
    '16; Сост.маршруты Ручное редактирование; Редактирование групп произвольных маршрутов',
    '17; Сост.маршруты Создание/Удаление маршрутов; Создание, удаление и изменение названия произвольных маршрутов',
    '18; Блокировка оборудования;Разрешение установки и снятия блокировки оборудования/датчиков',
    '19; Ручное управление;Разрешение изменения режима оборудования (АВТ / Руч / Откл)',
    '20; Запрет сообщений;Пользователь не видит сообщений',
    '21; Запрет архивов;Пользователю не доступны архивы',
    '22; Запрет графиков;Пользователю не доступны графики',
    '23; Запрет галочек;Пользователю не доступна установка галочек',
    '24; Запрет переключателей;Пользователю не доступна установка переключателей',
    '25; Запрет кнопок;Пользователь не может наживать управляющие кнопки',
    '26; Запрет выпадающих списков;Пользователь не может использовать выпадающие списки',
    '27; Запрет регулирующих ползунков;Пользователь не может использовать ползунки для регулирования'
  );

type
  TUsersForm = class(TForm)
    btAdd: TBitBtn;
    btEdit: TBitBtn;
    btDel: TBitBtn;
    BitBtn1: TBitBtn;
    Panel1: TPanel;
    Tree: TTreeView;
    Splitter1: TSplitter;
    Panel2: TPanel;
    Memo: TMemo;
    Splitter2: TSplitter;
    List: TListView;
    ActionList1: TActionList;
    ActionNew: TAction;
    Action2: TAction;
    Action3: TAction;
    procedure FormActivate(Sender: TObject);
    procedure btAddEditClick(Sender: TObject);
    procedure btDelClick(Sender: TObject);
    procedure TreeChange(Sender: TObject; Node: TTreeNode);
    procedure ActionNewExecute(Sender: TObject);
  private
    { Private declarations }
  public
    IdUser: integer;
  end;

  procedure ShowUsersControl(AOwner: TComponent);

  procedure initUsers;
  procedure preparePrevilegs;

  function  LoginUser: boolean;
  procedure LogoutUser;

  function CheckAccess(AccessLevel: integer; ShowMes: boolean = false;
        inverse: boolean = false): boolean;

  // Deprecated !!!
  function requestUserLogin(var id: Integer; var name: string; var info: string): Boolean;

  function isUserSuvervisor: boolean;

implementation

uses
  infodlg,
  connecting,
  DbUtils,
  RpVisualParams,
  RpVisualIni,
  UserProfile,
  UserLoginEx,
  UserControlEx,
  MesConst,
  DataMod,
  RpVisualGlobal,
  numbers,
  hyperstr,
  UserProp,
  UserLogin,
  MesLogging,
  rpMessages,
  inifiles,
  main;

{$R *.DFM}





procedure TUsersForm.FormActivate(Sender: TObject);
var
  i: integer;
begin
  Tree.Items.BeginUpdate;
  Tree.Items.Clear;

  if not isMesConnected then exit;

  try
    dm.QueryMes.Transaction.StartTransaction;

    dm.QueryMes.SQL.Text := 'SELECT IDUSER, NAME FROM USERS';
    dm.QueryMes.ExecQuery;

    while not dm.QueryMes.Eof do begin
      with Tree.Items.AddObject(nil, dm.QueryMes.FieldByName('NAME').AsString,
            pointer(dm.QueryMes.FieldByName('IDUSER').AsInteger) ) do
      dm.QueryMes.Next;
    end;
    dm.QueryMes.Transaction.Commit;

    for i:=0 to Tree.Items.Count-1 do
      if integer(Tree.Items[i].Data) = IdUser then Tree.Items[i].Selected := true;

  except
    dm.QueryMes.Transaction.Active := false;
    showInfoDlg('Ошибка чтения информации о пользователях!', mtError, [mbOk], 0);
  end;
  Tree.Items.EndUpdate;

  if Tree.Selected = nil then begin
    List.Items.Clear;
    Memo.Visible := false;
  end;
end;


procedure TUsersForm.TreeChange(Sender: TObject; Node: TTreeNode);
var
  id: integer;
  s: string;
begin
  if Tree.Selected = nil then exit;
  id := integer(Tree.Selected.Data);
  List.Items.BeginUpdate;
  List.Items.Clear;
  try
    dm.QueryMes.Transaction.StartTransaction;

    // info
    s := '';
    dm.QueryMes.SQL.Text := 'SELECT INFO FROM USERS WHERE IDUSER=' + inttostr(id);
    dm.QueryMes.ExecQuery;
    if dm.QueryMes.RecordCount > 0 then s := dm.QueryMes.Fields[0].AsString;
    s := trim(s);
    Memo.Lines.Text := s;
    Memo.Visible := not (s='');
    dm.QueryMes.Close;

    // previlegs
    dm.QueryMes.SQL.Text := 'SELECT P.NAME, P.INFO FROM PREVILEGS P, USERPREV S ' +
          'WHERE S.IDPREV=P.IDPREV AND S.IDUSER=' + inttostr(id);
    dm.QueryMes.ExecQuery;
    while not dm.QueryMes.Eof do with List.Items.Add do begin
      Caption := dm.QueryMes.Fields[0].AsString;
      SubItems.Add(dm.QueryMes.Fields[1].AsString);
      dm.QueryMes.Next;
    end;
    dm.QueryMes.Close;

    dm.QueryMes.Transaction.Commit;
  except
    dm.QueryMes.Transaction.Active := false;
  end;

  List.Items.EndUpdate;
end;


procedure TUsersForm.btAddEditClick(Sender: TObject);
var
  UserPropForm: TUserPropForm;
begin
  if (Tree.Selected=nil) and (Sender=btEdit) then exit;
  
  UserPropForm := TUserPropForm.Create(self);
  if Sender = btAdd then begin
    UserPropForm.id := IdUser;
    UserPropForm.NewFlag := true;
  end else begin
    UserPropForm.id := integer(Tree.Selected.Data);
    UserPropForm.NewFlag := false;
  end;
  if UserPropForm.ShowModal = mrOk then begin
    IdUser := UserPropForm.id;
    UserPropForm.Free;
    FormActivate(nil);
  end else
    UserPropForm.Free;
end;

procedure TUsersForm.btDelClick(Sender: TObject);
var
  i: integer;
begin
  if Tree.Selected = nil then exit;
  if integer(Tree.Selected.Data) = 1 then begin
    showInfoDlg('Системный администратор не подлежит удалению!', mtError, [mbOk], 0);
    exit;
  end;
  if showInfoDlg('Удалить пользователя?', mtConfirmation, [mbYes, mbNo], 0) <> mrYes then exit;
  try
    dm.WrQueryMes.Transaction.StartTransaction;
    dm.WrQueryMes.SQL.Text := 'DELETE FROM USERS WHERE IDUSER=' + inttostr(integer(Tree.Selected.Data));
    dm.WrQueryMes.ExecQuery;
    dm.WrQueryMes.Transaction.Commit;
  except
    dm.WrQueryMes.Transaction.Active := false;
  end;

  i := Tree.Selected.Index + 1;
  if i < Tree.Items.Count then IdUser := integer(Tree.Items[i].Data);
  FormActivate(nil);
end;


procedure TUsersForm.ActionNewExecute(Sender: TObject);
begin
  btAddEditClick(btAdd);
end;


////////////////////////////////////////////////////////////////////////////////

procedure ShowUsersControl(AOwner: TComponent);
var
  UsersForm: TUsersForm;
begin
  if not isMesloggingConnected then exit;

  UsersForm := TUsersForm.Create(AOwner);
  UsersForm.ShowModal;
  UsersForm.Free;
end;


procedure initUsers;
begin
  if not isMesloggingConnected then exit;

  try
    if not( (table_exist(dm.pFIBDbMes, 'PREVILEGS')) and
       (table_exist(dm.pFIBDbMes, 'USERS')) and
       (table_exist(dm.pFIBDbMes, 'USERPREV')) ) then
    begin
      showInfoDlg('Таблицы пользователей не найдены!', mtError, [mbOk], 0);
      Exit;
    end;

    preparePrevilegs;

    initUserEx;
  except
  end;
end;



procedure preparePrevilegs;
var
  s, ss, s_name, s_info, sprvlg: string;
  n,i,k: integer;
  ins_flag, upd_flag: boolean;
begin
  try
    sprvlg := '';
    for k:=1 to length(prvlg) do begin
      s := prvlg[k];

      s := trim(s);
      if (s = '') or (copy(s, 1, 2) = '//') then continue;

      i:=1;
      ss:=trim(Parse(s, ';', i));
      s_name:=trim(Parse(s, ';', i));
      s_info:=trim(Parse(s, ';', i));
      val(ss, n, i);

//      ins_flag := false;
      upd_flag := false;

      sprvlg := sprvlg + inttostr(n) + ',';

      dm.QueryMes.Transaction.StartTransaction;
      dm.WrQueryMes.Transaction.StartTransaction;

      dm.QueryMes.SQL.Text := 'SELECT NAME, INFO FROM PREVILEGS WHERE IDPREV=' +
          inttostr(n);
      dm.QueryMes.ExecQuery;
      ins_flag := dm.QueryMes.RecordCount = 0;
      if not ins_flag then
        upd_flag := not ((dm.QueryMes.FieldByName('NAME').AsString = s_name) and
              (dm.QueryMes.FieldByName('INFO').AsString = s_info));
      dm.QueryMes.Close;

      dm.QueryMes.SQL.Clear;
      if ins_flag then
        dm.WrQueryMes.SQL.Text := 'INSERT INTO PREVILEGS (NAME, INFO, IDPREV) VALUES (' +
              #39 + s_name + #39','#39 + s_info + #39',' + inttostr(n) +')';

      if upd_flag then
        dm.WrQueryMes.SQL.Text := 'UPDATE PREVILEGS SET NAME='#39 + s_name + #39',' +
              'INFO='#39 + s_info + #39' WHERE IDPREV=' + inttostr(n);

      if (ins_flag) or (upd_flag) then dm.WrQueryMes.ExecQuery;

      dm.WrQueryMes.Transaction.Commit;
      dm.QueryMes.Transaction.Commit;

    end;
  except
    dm.QueryMes.Transaction.Active:= false;
    dm.WrQueryMes.Transaction.Active:= false;
    showInfoDlg('Ошибка записи в таблицу PREVILEG!', mtError, [mbOk], 0);
  end;
end;



function LoginUser: boolean;
var
  reconnectMode: boolean;
begin
  Result := True;
  if not isMesloggingConnected then exit;

  Result := false;
  if not isMesConnected then Exit;

  reconnectMode := CurUserId > 0;

  loadLastUserIdIni();

  if modeUserEx then begin
    result := doUserLoginEx(userEx);
    if Result then
      updateOrInsertCurUser;
  end else begin
    result := doUserLogin();
  end;

  if result then begin
    saveLastUserIdIni();
    Form1.lbUser.Caption := CurUserName;
    if not reconnectMode then
      SaveMessageText(mcLogin_text, CurUserName, '', mcLogin_bc, mcLogin_fc);
  end else begin
    CurUserId := 0;
    CurUserName := '';
  end;
end;


procedure LogoutUser;
begin
  if not isMesloggingConnected then exit;
  if CurUserId = 0 then Exit;

  Form1.lbUser.Caption := '';
  SaveMessageText(mcLogout_text, CurUserName, '', mcLogout_bc, mcLogout_fc);

  CurUserId := 0;
  CurUserName := '';
end;


function CheckAccess(AccessLevel: integer; ShowMes: boolean; inverse: boolean): boolean;
var
  flag: boolean;
  s: string;
begin
  result := true;
  if not isMesloggingConnected then exit;
  if CurUserId=1 then exit;

  if not isMesConnected then begin
    Result := false;
    exit;
  end;

  flag := false;
  try
    dm.QueryMes.Transaction.StartTransaction;

    dm.QueryMes.SQL.Text := 'SELECT COUNT(*) FROM USERPREV WHERE IDUSER=' +
          inttostr(CurUserId)  + ' AND IDPREV=' + inttostr(AccessLevel);
    dm.QueryMes.ExecQuery;
    if inverse then
      flag := dm.QueryMes.Fields[0].AsInteger = 0
    else
      flag := dm.QueryMes.Fields[0].AsInteger > 0;
    dm.QueryMes.Close;

    if (not flag) and (ShowMes) then begin
      dm.QueryMes.SQL.Text := 'SELECT NAME FROM PREVILEGS WHERE IDPREV=' + inttostr(AccessLevel);
      dm.QueryMes.ExecQuery;
      if dm.QueryMes.RecordCount > 0 then
        s := dm.QueryMes.Fields[0].AsString
      else
        s := 'неизвестный код привилегии - ' + inttostr(AccessLevel);
      dm.QueryMes.Close;

      showInfoDlg('Ограничение прав доступа:'#13#13 + s, mtInformation,  [mbOk], 0)
    end;

    dm.QueryMes.Transaction.Commit;
  except
    dm.QueryMes.Transaction.Active := false;
  end;
  result := flag;
end;


// Deprecated !!!
// Can be used for back compatibility only !!!
function requestUserLogin(var id: Integer; var name: string; var info: string): Boolean;
var
  saveCurUserId: integer;
  saveCurUserName: String;
  saveCurUserInfo: String;
begin
  saveCurUserId := CurUserId;
  saveCurUserName := CurUserName;
  saveCurUserInfo := CurUserInfo;

  result := LoginUser;
  id := CurUserId;
  name := CurUserName;
  info := CurUserInfo;

  CurUserId := saveCurUserId;
  CurUserName := saveCurUserName;
  CurUserInfo := saveCurUserInfo;
end;


function isUserSuvervisor: boolean;
begin
  Result := CurUserId = USER_SUPERVISOR;
end;

initialization
  UserControlEx.userEx := TUserProfile.Create;

finalization
  UserControlEx.userEx.free;

end.
