| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015 |
- <?php
- /**
- * The model file of user module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Chunsheng Wang <chunsheng@cnezsoft.com>
- * @package user
- * @version $Id: model.php 5005 2013-07-03 08:39:11Z chencongzhi520@gmail.com $
- * @link https://www.zentao.net
- */
- ?>
- <?php
- class userModel extends model
- {
- /**
- * 创建或编辑用户前的检查。
- * Check before create or edit a user.
- *
- * @param object $user
- * @param bool $canNoPassword
- * @access public
- * @return bool
- */
- public function checkBeforeCreateOrEdit($user, $canNoPassword = false)
- {
- if(strtolower($user->account) == 'guest') dao::$errors['account'][] = sprintf($this->lang->user->error->reserved, $user->account);
- $this->checkPassword($user, $canNoPassword);
- $this->checkVerifyPassword($user->verifyPassword);
- return !dao::isError();
- }
- /**
- * 批量创建用户前的检查。
- * Check before batch creating users.
- *
- * @param array $users
- * @param string $verifyPassword
- * @access public
- * @return bool
- */
- public function checkBeforeBatchCreate($users, $verifyPassword)
- {
- if(!$users) return true;
- $accounts = array_map(function($user){return $user->account;}, $users);
- $accounts = $this->dao->select('account')->from(TABLE_USER)->where('account')->in($accounts)->fetchPairs();
- foreach($users as $key => $user)
- {
- if(empty($user->account)) continue;
- if(strtolower($user->account) == 'guest') dao::$errors["account[{$key}]"][] = $this->lang->user->error->reserved;
- if(isset($accounts[$user->account])) dao::$errors["account[{$key}]"][] = sprintf($this->lang->error->unique, $this->lang->user->account, $user->account);
- if(!validater::checkAccount($user->account)) dao::$errors["account[{$key}]"][] = sprintf($this->lang->error->account, $this->lang->user->account);
- if(empty($user->realname)) dao::$errors["realname[{$key}]"][] = sprintf($this->lang->error->notempty, $this->lang->user->realname);
- if(empty($user->visions)) dao::$errors["visions[{$key}][]"][] = sprintf($this->lang->error->notempty, $this->lang->user->visions);
- if(empty($user->password)) dao::$errors["password[{$key}]"][] = sprintf($this->lang->error->notempty, $this->lang->user->password);
- if(!empty($user->password) && !validater::checkReg($user->password, '|(.){6,}|')) dao::$errors["password[{$key}]"][] = $this->lang->user->error->password;
- if(!empty($user->email) && !validater::checkEmail($user->email)) dao::$errors["email[{$key}]"][] = sprintf($this->lang->error->email, $this->lang->user->email);
- if(!empty($user->phone) && !validater::checkPhone($user->phone)) dao::$errors["phone[{$key}]"][] = sprintf($this->lang->error->phone, $this->lang->user->phone);
- if(!empty($user->mobile) && !validater::checkMobile($user->mobile)) dao::$errors["mobile[{$key}]"][] = sprintf($this->lang->error->mobile, $this->lang->user->mobile);
- if(empty($user->gender)) dao::$errors["gender[{$key}]"][] = sprintf($this->lang->error->notempty, $this->lang->user->gender);
- /* 检查密码强度是否符合安全设置。*/
- /* Check if the password strength meets the security settings. */
- if(isset($this->config->safe->mode) && $this->computePasswordStrength($user->password) < $this->config->safe->mode) dao::$errors["password[{$key}]"][] = $this->lang->user->error->weakPassword;
- /* 检查明文的弱密码。*/
- /* Check the weak password in clear text. */
- if(!empty($this->config->safe->changeWeak))
- {
- if(!isset($this->config->safe->weak)) $this->app->loadConfig('admin');
- if(strpos(",{$this->config->safe->weak},", ",{$user->password},") !== false) dao::$errors["password[{$key}]"][] = sprintf($this->lang->user->error->dangerPassword, $this->config->safe->weak);
- }
- $accounts[$user->account] = $user->account;
- }
- $this->checkVerifyPassword($verifyPassword);
- return !dao::isError();
- }
- /**
- * 批量编辑用户前的检查。
- * Check before batch editing users.
- *
- * @param array $users
- * @param string $verifyPassword
- * @access public
- * @return bool
- */
- public function checkBeforeBatchUpdate($users, $verifyPassword)
- {
- if(!$users) return true;
- foreach($users as $key => $user)
- {
- if(empty($user->realname)) dao::$errors["realname[{$key}]"][] = sprintf($this->lang->error->notempty, $this->lang->user->realname);
- if(empty($user->visions)) dao::$errors["visions[{$key}][]"][] = sprintf($this->lang->error->notempty, $this->lang->user->visions);
- if(!empty($user->email) && !validater::checkEmail($user->email)) dao::$errors["email[{$key}]"][] = sprintf($this->lang->error->email, $this->lang->user->email);
- if(!empty($user->phone) && !validater::checkPhone($user->phone)) dao::$errors["phone[{$key}]"][] = sprintf($this->lang->error->phone, $this->lang->user->phone);
- if(!empty($user->mobile) && !validater::checkMobile($user->mobile)) dao::$errors["mobile[{$key}]"][] = sprintf($this->lang->error->mobile, $this->lang->user->mobile);
- }
- $this->checkVerifyPassword($verifyPassword);
- return !dao::isError();
- }
- /**
- * 检查密码强度。
- * Check the posted password.
- *
- * @param object $user
- * @param bool $canNoPassword
- * @access public
- * @return bool
- */
- public function checkPassword($user, $canNoPassword = false)
- {
- if(empty($user->password1))
- {
- if(!$canNoPassword) dao::$errors['password1'][] = sprintf($this->lang->error->notempty, $this->lang->user->password);
- return !dao::isError();
- }
- /* 检查密码强度是否符合安全设置。*/
- /* Check if the password strength meets the security settings. */
- if(isset($this->config->safe->mode) && ($user->passwordStrength < $this->config->safe->mode))
- {
- dao::$errors['password1'][] = zget($this->lang->user->placeholder->passwordStrengthCheck, $this->config->safe->mode, $this->lang->user->weakPassword);
- }
- else if($user->passwordLength < 6)
- {
- dao::$errors['password1'][] = zget($this->lang->user->placeholder->passwordStrengthCheck, 0, $this->lang->user->weakPassword);
- }
- if($user->password1 != $user->password2) dao::$errors['password1'][] = $this->lang->error->passwordsame;
- if(!empty($this->config->safe->changeWeak))
- {
- if(!isset($this->config->safe->weak)) $this->app->loadConfig('admin');
- /* 检查明文的弱密码。*/
- /* Check the weak password in clear text. */
- if(strpos(",{$this->config->safe->weak},", ",{$user->password1},") !== false) dao::$errors['password1'] = sprintf($this->lang->user->errorWeak, $this->config->safe->weak);
- /* 检查加密后的弱密码。*/
- /* Check for encrypted weak password. */
- $weaks = array();
- foreach(explode(',', $this->config->safe->weak) as $weak) $weaks[] = md5(trim($weak));
- if(in_array(substr($user->password1, 0, 32), $weaks)) dao::$errors['password1'] = sprintf($this->lang->user->errorWeak, $this->config->safe->weak);
- }
- return !dao::isError();
- }
- /**
- * 检查当前用户密码是否正确。
- * Check if the current user password is correct.
- *
- * @param string $verifyPassword
- * @access public
- * @return bool
- */
- public function checkVerifyPassword($verifyPassword)
- {
- /* API has no verifyPassword. */
- if($this->app->apiVersion == 'v2') return true;
- if(empty($verifyPassword) || $verifyPassword != md5($this->app->user->password . $this->session->rand)) dao::$errors['verifyPassword'][] = $this->lang->user->error->verifyPassword;
- return !dao::isError();
- }
- /**
- * 获取用户列表。
- * Get user list.
- *
- * @param string $params
- * @param string $fields
- * @access public
- * @return array
- */
- public function getList($params = 'nodeleted', $fields = '*')
- {
- return $this->dao->select($fields)->from(TABLE_USER)
- ->where('1 = 1')
- ->beginIF(strpos($params, 'all') === false)->andWhere('type')->eq('inside')->fi()
- ->beginIF(strpos($params, 'nodeleted') !== false)->andWhere('deleted')->eq(0)->fi()
- ->orderBy('account')
- ->fetchAll('', false);
- }
- /**
- * 根据用户 id 列表获取用户。
- * Get user list by id list.
- *
- * @param array $idList
- * @access public
- * @return array
- */
- public function getListByIdList($idList)
- {
- if(!$idList) return array();
- return $this->dao->select('*')->from(TABLE_USER)
- ->where('deleted')->eq('0')
- ->andWhere('id')->in($idList)
- ->orderBy('id')
- ->fetchAll('id');
- }
- /**
- * 根据用户名列表获取用户信息。
- * Get user info by account list.
- *
- * @param array $accounts
- * @param string $keyField
- * @access public
- * @return array
- */
- public function getListByAccounts($accounts, $keyField = 'id')
- {
- if(empty($accounts)) return array();
- return $this->dao->select('id,account,realname,avatar,role')->from(TABLE_USER)
- ->where('account')->in($accounts)
- ->fetchAll($keyField);
- }
- /**
- * 获取用户名和真实姓名的键值对。
- * Get account and realname pairs.
- *
- * @param string $params noletter|noempty|nodeleted|noclosed|withguest|pofirst|devfirst|qafirst|pmfirst|realname|outside|inside|all, can be sets of theme
- * @param string|array $usersToAppended account1,account2
- * @param int $maxCount
- * @param string|array $accounts
- * @access public
- * @return array
- */
- public function getPairs($params = '', $usersToAppended = '', $maxCount = 0, $accounts = '')
- {
- if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getUserPairs();
- /* 设置查询字段、条件字段、排序字段和索引字段。
- * Set query fields, condition fields, order fields and index field.
- *
- * 如果参数中有 xxfirst,使用 INSTR 函数获取角色字段在排序字符串中的位置,以确保用户在角色排序中排在前面。
- * If there's xxfirst in the params, use INSTR function to get the position of role fields in a order string,
- * thus to make sure users of this role at first.
- */
- $fields = 'id, account, realname, deleted';
- if(strpos($params, 'pofirst') !== false) $fields .= ", INSTR(',pd,po,', role) AS roleOrder";
- if(strpos($params, 'pdfirst') !== false) $fields .= ", INSTR(',po,pd,', role) AS roleOrder";
- if(strpos($params, 'qafirst') !== false) $fields .= ", INSTR(',qd,qa,', role) AS roleOrder";
- if(strpos($params, 'qdfirst') !== false) $fields .= ", INSTR(',qa,qd,', role) AS roleOrder";
- if(strpos($params, 'pmfirst') !== false) $fields .= ", INSTR(',td,pm,', role) AS roleOrder";
- if(strpos($params, 'devfirst')!== false) $fields .= ", INSTR(',td,pm,qd,qa,dev,', role) AS roleOrder";
- $type = (strpos($params, 'outside') !== false) ? 'outside' : 'inside';
- $orderBy = (strpos($params, 'first') !== false) ? 'roleOrder DESC, account' : 'account';
- $keyField = (strpos($params, 'useid') !== false) ? 'id' : "account";
- $users = $this->dao->select($fields)->from(TABLE_USER)
- ->where('1=1')
- ->beginIF(strpos($params, 'nodeleted') !== false || empty($this->config->user->showDeleted))->andWhere('deleted')->eq('0')->fi()
- ->beginIF(strpos($params, 'all') === false)->andWhere('type')->eq($type)->fi()
- ->beginIF($accounts)->andWhere('account')->in($accounts)->fi()
- ->beginIF($this->config->vision && $this->app->rawModule !== 'kanban')->andWhere("FIND_IN_SET('{$this->config->vision}', visions)")->fi()
- ->orderBy($orderBy)
- ->beginIF($maxCount)->limit($maxCount)->fi()
- ->fetchAll($keyField);
- $this->processMoreLink($params, $usersToAppended, $maxCount, count($users));
- if($usersToAppended) $users += $this->fetchExtraUsers($usersToAppended, $fields, $keyField);
- $users = $this->processDisplayValue($users, $params);
- $users = $this->setCurrentUserFirst($users);
- /* Append empty, closed, and guest users. */
- if(strpos($params, 'noclosed') === false) $users = $users + array('closed' => 'Closed');
- if(strpos($params, 'withguest') !== false) $users = $users + array('guest' => 'Guest');
- return $users;
- }
- /**
- * 处理获取更多用户的链接。
- * Process the more link.
- *
- * @param string $params
- * @param string|array $usersToAppended
- * @param int $maxCount
- * @param int $userCount
- * @access public
- * @return bool
- */
- public function processMoreLink($params, $usersToAppended, $maxCount, $userCount)
- {
- unset($this->config->user->moreLink);
- if($maxCount && $maxCount == $userCount)
- {
- if(is_array($usersToAppended)) $usersToAppended = implode(',', $usersToAppended);
- $moreLinkParams = "params={$params}&usersToAppended={$usersToAppended}";
- $moreLink = helper::createLink('user', 'ajaxGetMore');
- $this->config->user->moreLink = $moreLink . (strpos($moreLink, '?') === false ? '?' : '&') . "params=" . base64_encode($moreLinkParams) . '&search={search}';
- }
- return true;
- }
- /**
- * 根据用户名获取额外的用户。
- * Get extra users by account.
- *
- * @param string|array $usersToAppended
- * @param string $fields
- * @param string $keyField
- * @access public
- * @return array
- */
- public function fetchExtraUsers($usersToAppended, $fields, $keyField)
- {
- if(!$usersToAppended) return array();
- return $this->dao->select($fields)->from(TABLE_USER)->where('account')->in($usersToAppended)->fetchAll($keyField);
- }
- /**
- * 处理用户的显示名称。
- * Process the display value of users.
- *
- * @param array $users
- * @param string $params
- * @access public
- * @return array
- */
- public function processDisplayValue($users, $params)
- {
- foreach($users as $account => $user)
- {
- if(strpos($params, 'showid') !== false)
- {
- $users[$account] = $user->id;
- continue;
- }
- $firstLetter = ucfirst(mb_substr($user->account, 0, 1)) . ':';
- if(strpos($params, 'noletter') !== false || !empty($this->config->isINT)) $firstLetter = '';
- $users[$account] = $firstLetter . (($user->deleted && strpos($params, 'realname') === false) ? $user->account : ($user->realname ?: $user->account));
- }
- return $users;
- }
- /**
- * 获取用户名和头像的键值对。
- * Get account and avatar pairs.
- *
- * @param string $params
- * @access public
- * @return array
- */
- public function getAvatarPairs($params = 'nodeleted')
- {
- $avatarPairs = array();
- $userList = $this->getList($params, 'account,avatar');
- foreach($userList as $user) $avatarPairs[$user->account] = $user->avatar;
- return $avatarPairs;
- }
- /**
- * 获取源代码账号和真实姓名/用户名的键值对。
- * Get account and realname pairs.
- *
- * @param string $field
- * @access public
- * @return array
- */
- public function getCommiters($field = 'realname')
- {
- $rawCommiters = $this->dao->select('commiter, account, realname')->from(TABLE_USER)->where('commiter')->ne('')->fetchAll();
- if(!$rawCommiters) return array();
- $commiters = array();
- foreach($rawCommiters as $commiter)
- {
- $userCommiters = explode(',', $commiter->commiter);
- foreach($userCommiters as $userCommiter) $commiters[$userCommiter] = $commiter->$field ?: $commiter->account;
- }
- return $commiters;
- }
- /**
- * 获取用户名、真实姓名和邮箱组成的用户列表。
- * Get user list with account, realname and email.
- *
- * @param string|array $users
- * @access public
- * @return array
- */
- public function getRealNameAndEmails($users)
- {
- if(!$users) return array();
- return $this->dao->select("account, email, IF(realname = '', account, realname) AS realname")->from(TABLE_USER)->where('account')->in($users)->fetchAll('account');
- }
- /**
- * 获取用户名和角色名的键值对。
- * Get account and role pairs.
- *
- * @param string|array $users
- * @access public
- * @return array
- */
- public function getUserRoles($users)
- {
- if(!$users) return array();
- $users = $this->dao->select('account, role')->from(TABLE_USER)->where('account')->in($users)->fetchPairs();
- if(!$users) return array();
- foreach($users as $account => $role) $users[$account] = zget($this->lang->user->roleList, $role);
- return $users;
- }
- /**
- * 根据指定字段的值获取一个用户。
- * Get a user by the value of the specified field.
- *
- * @param string $userID
- * @param string $field id|account
- * @access public
- * @return object|bool
- */
- public function getById($userID, $field = 'account')
- {
- /* 如果 userID 参数为空并且当前用户是游客,返回当前用户,以确保仪表盘页面正常工作。*/
- /* If the userID param is empty and the current user is guest, return the current user to make sure the dashboard page works well. */
- if(empty($userID) && $this->app->user->account == 'guest') return $this->app->user;
- if($field == 'id') $userID = (int)$userID;
- if($field == 'account') $userID = trim($userID);
- $user = $this->dao->select('*')->from(TABLE_USER)->where("`$field`")->eq($userID)->fetch();
- if(!$user) return false;
- return $user;
- }
- /**
- * 根据自定义查询语句获取用户。
- * Get users by custom query.
- *
- * @param string $browseType inside|outside|all
- * @param string $query
- * @param object $pager
- * @param string $orderBy
- * @access public
- * @return array
- */
- public function getByQuery($browseType = 'inside', $query = '', $pager = null, $orderBy = 'id')
- {
- return $this->dao->select('*')->from(TABLE_USER)
- ->where('deleted')->eq('0')
- ->beginIF($query)->andWhere($query)->fi()
- ->beginIF($browseType == 'inside')->andWhere('type')->eq('inside')->fi()
- ->beginIF($browseType == 'outside')->andWhere('type')->eq('outside')->fi()
- ->beginIF($this->config->vision)->andWhere("FIND_IN_SET('{$this->config->vision}', visions)")->fi()
- ->orderBy($orderBy)
- ->page($pager)
- ->fetchAll();
- }
- /**
- * 添加一个用户。
- * Create a user.
- *
- * @param object $user
- * @access public
- * @return false|int
- */
- public function create($user)
- {
- $this->checkBeforeCreateOrEdit($user);
- $this->dao->begin();
- $requiredFields = $this->config->user->create->requiredFields;
- if($user->type == 'outside')
- {
- if($user->new) $user->company = $this->createCompany($user->newCompany);
- $requiredFields = trim(str_replace(array(',dept,', ',commiter,'), '', ',' . $requiredFields . ','), ',');
- }
- $this->dao->insert(TABLE_USER)->data($user, 'new,newCompany,password1,password2,group,verifyPassword,passwordLength,passwordStrength')
- ->batchCheck($requiredFields, 'notempty')
- ->checkIF($user->account, 'account', 'unique')
- ->checkIF($user->account, 'account', 'account')
- ->checkIF($user->email, 'email', 'email')
- ->autoCheck()
- ->exec();
- if(dao::isError()) return $this->rollback();
- $userID = $this->dao->lastInsertID();
- /* 创建用户组,更新用户视图并记录日志。*/
- /* Create user group, update user view and save log. */
- $groups = array_filter($user->group);
- if($groups) $this->createUserGroup($groups, $user->account);
- $this->loadModel('action')->create('user', $userID, 'Created');
- if(dao::isError()) return $this->rollback();
- $this->dao->commit();
- return $userID;
- }
- /**
- * 创建一个外部公司。
- * Create a outside company.
- *
- * @param string $companyName
- * @access public
- * @return int
- */
- public function createCompany($companyName)
- {
- if(empty($companyName))
- {
- dao::$errors['newCompany'][] = sprintf($this->lang->error->notempty, $this->lang->user->company);
- return 0;
- }
- $company = new stdClass();
- $company->name = $companyName;
- $this->dao->insert(TABLE_COMPANY)->data($company)->exec();
- return $this->dao->lastInsertID();
- }
- /**
- * 创建用户组。
- * Create user group.
- *
- * @param array $groups
- * @param string $account
- * @access public
- * @return bool
- */
- public function createUserGroup($groups, $account)
- {
- if(empty($groups) || empty($account)) return false;
- $userGroup = new stdclass();
- $userGroup->account = $account;
- $userGroup->project = '';
- foreach($groups as $group)
- {
- $userGroup->group = $group;
- $this->dao->replace(TABLE_USERGROUP)->data($userGroup)->exec();
- }
- return !dao::isError();
- }
- /**
- * 批量创建用户。
- * Batch create users.
- *
- * @param array $users
- * @param string $verifyPassword
- * @access public
- * @return bool|array
- */
- public function batchCreate($users, $verifyPassword)
- {
- if(!$users) return false;
- $this->checkBeforeBatchCreate($users, $verifyPassword);
- if(dao::isError()) return false;
- $this->loadModel('action');
- $this->dao->begin();
- $userIdList = array();
- $preCompany = 0;
- foreach($users as $index => $user)
- {
- if(empty($user->account)) continue;
- $user->password = md5($user->password);
- if($user->type == 'outside')
- {
- if($user->new) $user->company = $this->createCompany($user->newCompany);
- if($this->post->company[$index] != 'ditto') $preCompany = $user->company;
- if($this->post->company[$index] == 'ditto') $user->company = $preCompany;
- }
- $this->dao->insert(TABLE_USER)->data($user, 'new,newCompany,group')->autoCheck()->exec();
- if(dao::isError()) return $this->rollback();
- $userID = $this->dao->lastInsertID();
- /* 创建用户组,更新用户视图并记录日志。*/
- /* Create user group, update user view and save log. */
- $groups = array_filter($user->group);
- if($groups) $this->createUserGroup($groups, $user->account);
- $this->action->create('user', $userID, 'Created');
- if(dao::isError()) return $this->rollback();
- $userIdList[] = $userID;
- }
- $this->dao->commit();
- return $userIdList;
- }
- /**
- * 更新一个用户。
- * Update a user.
- *
- * @param object $user
- * @access public
- * @return bool
- */
- public function update($user)
- {
- $oldUser = $this->getById($user->id, 'id');
- $this->checkBeforeCreateOrEdit($user, true);
- $this->dao->begin();
- if(!isset($user->type)) $user->type = $oldUser->type;
- if($user->type == 'outside' && $user->new) $user->company = $this->createCompany($user->newCompany);
- /* 获取所有的联系方式字段。*/
- /* Get all contact fields. */
- $allContactFields = array_keys($this->lang->user->contactFieldList);
- /* 获取可用的联系方式字段,转为数组并去空、去重。*/
- /* Get available contact fields, convert to array and remove empty and duplicate. */
- $availableContactFields = array_unique(array_filter(explode(',', trim($this->config->user->contactField, ','))));
- /* 获取不可用的联系方式字段。*/
- /* Get unavailable contact fields. */
- $unAvailableContactFields = array_diff($allContactFields, $availableContactFields);
- /* 从配置文件获取必填项字段,转为数组并去空、去重。*/
- /* Get required fields from config file, convert to array and remove empty and duplicate. */
- $requiredFields = array_unique(array_filter(explode(',', trim($this->config->user->edit->requiredFields, ','))));
- /* 从必填项字段中去除不可用的联系方式字段。*/
- /* Remove unavailable contact fields from available fields. */
- $requiredFields = implode(',', array_diff($requiredFields, $unAvailableContactFields));
- $this->dao->update(TABLE_USER)->data($user, 'new,newCompany,password1,password2,group,verifyPassword,passwordLength,passwordStrength')
- ->batchCheck($requiredFields, 'notempty')
- ->checkIF($user->account, 'account', 'unique', "id != '$user->id'")
- ->checkIF($user->account, 'account', 'account')
- ->checkIF($user->email, 'email', 'email')
- ->checkIF($user->phone, 'phone', 'phone')
- ->checkIF($user->mobile, 'mobile', 'mobile')
- ->autoCheck()
- ->where('id')->eq($user->id)
- ->exec();
- if(dao::isError()) return $this->rollBack();
- /* 更新用户组和用户视图并记录积分和日志。*/
- /* Update user group and user view, and save log and score. */
- $this->checkAccountChange($oldUser->account, $user->account);
- $this->checkGroupChange($user);
- $this->loadModel('score')->create('user', 'editProfile');
- $changes = common::createChanges($oldUser, $user);
- if($changes)
- {
- $actionID = $this->loadModel('action')->create('user', $user->id, 'edited');
- $this->action->logHistory($actionID, $changes);
- }
- if(dao::isError()) return $this->rollBack();
- if(!empty($user->password) && $user->password != $oldUser->password) $this->userTao->deleteImUserDevice($user->id);
- $this->dao->commit();
- /* 更新当前用户的信息。*/
- /* Update current user's info. */
- if($user->account == $this->app->user->account)
- {
- if(!empty($user->password)) $this->app->user->password = $user->password;
- $this->app->user->realname = $user->realname;
- $this->app->user->role = isset($user->role) ? $user->role : $oldUser->role;
- }
- return true;
- }
- /**
- * 检查用户名是否发生变化。
- * Check if the account changed.
- *
- * @param string $oldAccount
- * @param string $newAccount
- * @access public
- * @return bool
- */
- public function checkAccountChange($oldAccount, $newAccount)
- {
- if($oldAccount == $newAccount) return false;
- /* 更新用户组和用户视图。*/
- /* Update the user group and user view. */
- $this->dao->update(TABLE_USERGROUP)->set('account')->eq($newAccount)->where('account')->eq($oldAccount)->exec();
- $this->dao->update(TABLE_USERVIEW)->set('account')->eq($newAccount)->where('account')->eq($oldAccount)->exec();
- /* 如果旧用户名是公司管理员,则更新公司管理员。*/
- /* If the old account is company admin, update the company admin. */
- if(strpos($this->app->company->admins, ',' . $oldAccount . ',') !== false)
- {
- $admins = str_replace(',' . $oldAccount . ',', ',' . $newAccount . ',', $this->app->company->admins);
- $this->dao->update(TABLE_COMPANY)->set('admins')->eq($admins)->where('id')->eq($this->app->company->id)->exec();
- if(dao::isError()) return false;
- $this->app->company->admins = $admins;
- }
- return !dao::isError();
- }
- /**
- * 检查权限组是否发生变化。
- * Check if the group changed.
- *
- * @param object $user
- * @access public
- * @return bool
- */
- public function checkGroupChange($user)
- {
- $oldGroups = array_keys($this->loadModel('group')->getByAccount($user->account, true));
- $newGroups = array_unique(array_filter($user->group));
- sort($oldGroups);
- sort($newGroups);
- if(implode(',', $oldGroups) == implode(',', $newGroups)) return false;
- /* 如果权限组发生变化,则删除原有的权限组,重新创建并更新用户视图。*/
- /* If the group changed, delete the old group, create new group and update user view. */
- $projectGroups = $this->dao->select('id')->from(TABLE_GROUP)->where('project')->ne(0)->fetchPairs();
- $this->dao->delete()->from(TABLE_USERGROUP)
- ->where('account')->eq($user->account)
- ->andWhere('`group`')->notin($projectGroups)
- ->exec();
- if($newGroups) $this->createUserGroup($newGroups, $user->account);
- return !dao::isError();
- }
- /**
- * 批量编辑用户。
- * Batch update user.
- *
- * @param array $users
- * @param string $verifyPassword
- * @access public
- * @return bool
- */
- public function batchUpdate($users, $verifyPassword)
- {
- if(!$users) return false;
- $this->checkBeforeBatchUpdate($users, $verifyPassword);
- if(dao::isError()) return false;
- $this->loadModel('action');
- $accounts = array_map(function($user){return $user->account;}, $users);
- $oldUsers = $this->dao->select('*')->from(TABLE_USER)->where('account')->in($accounts)->fetchAll('id');
- $this->dao->begin();
- foreach($users as $id => $user)
- {
- $this->dao->update(TABLE_USER)->data($user)->where('id')->eq($id)->autoCheck()->exec();
- if(dao::isError()) return $this->rollback();
- /* 更新用户组和用户视图并记录日志。*/
- /* Update user group and user view, and save log and score. */
- $oldUser = $oldUsers[$id];
- $changes = common::createChanges($oldUser, $user);
- if($changes)
- {
- $actionID = $this->action->create('user', $id, 'edited');
- $this->action->logHistory($actionID, $changes);
- }
- if(dao::isError()) return $this->rollback();
- /* 更新当前用户的信息。*/
- /* Update current user's info. */
- if($user->account == $this->app->user->account)
- {
- $this->app->user->realname = $user->realname;
- $this->app->user->role = $user->role;
- }
- }
- $this->dao->commit();
- return true;
- }
- /**
- * 更新当前用户的密码。
- * Update current user's password.
- *
- * @param object $user
- * @access public
- * @return bool
- */
- public function updatePassword($user)
- {
- $this->checkPassword($user);
- if($user->originalPassword != md5($this->app->user->password . $this->session->rand)) dao::$errors['originalPassword'][] = $this->lang->user->error->originalPassword;
- if(dao::isError()) return false;
- $this->dao->update(TABLE_USER)->set('password')->eq($user->password)->where('id')->eq($this->app->user->id)->exec();
- if(dao::isError()) return false;
- $this->userTao->deleteImUserDevice($this->app->user->id);
- $this->loadModel('score')->create('user', 'changePassword', $this->computePasswordStrength($user->password1));
- $this->app->user->password = $user->password;
- $this->app->user->modifyPassword = false;
- $this->app->user->modifyPasswordReason = '';
- $_SESSION['user'] = $this->app->user;
- return true;
- }
- /**
- * 重置密码。
- * Reset password.
- *
- * @param object $user
- * @access public
- * @return bool
- */
- public function resetPassword($user)
- {
- $oldUser = $this->getById($user->account);
- if(!$oldUser)
- {
- dao::$errors['account'] = $this->lang->user->error->noUser;
- return false;
- }
- $this->checkPassword($user);
- $this->dao->update(TABLE_USER)->set('password')->eq($user->password)->where('account')->eq($user->account)->exec();
- return !dao::isError();
- }
- /**
- * 验证用户并设置相关属性。
- * Identify user and set related properties.
- *
- * @param string $account the user account
- * @param string $password the user password or auth hash
- * @param int $passwordStrength the user password strength
- * @access public
- * @return bool|object
- */
- public function identify($account, $password, $passwordStrength = 0)
- {
- if(!$account || !$password) return false;
- if(!validater::checkAccount($account)) return false;
- $user = $this->identifyUser($account, $password);
- if(!$user) return false;
- $ip = helper::getRemoteIp();
- $last = helper::now();
- $user = $this->checkNeedModifyPassword($user, $passwordStrength);
- $user->last = $last;
- $user->admin = strpos($this->app->company->admins, ",{$user->account},") !== false;
- if($this->app->isServing())
- {
- $this->dao->update(TABLE_USER)->set('visits = visits + 1')->set('ip')->eq($ip)->set('last')->eq($last)->where('account')->eq($account)->exec();
- /* 登录后创建周期性待办。*/
- /* Create cycle todo after login. */
- $todoList = $this->dao->select('*')->from(TABLE_TODO)->where('cycle')->eq(1)->andWhere('deleted')->eq('0')->andWhere('account')->eq($user->account)->fetchAll('id');
- if($todoList) $this->loadModel('todo')->createByCycle($todoList);
- }
- if($user->avatar)
- {
- $avatarRoot = substr($user->avatar, 0, strpos($user->avatar, 'data/upload/'));
- if($this->config->webRoot != $avatarRoot) $user->avatar = substr_replace($user->avatar, $this->config->webRoot, 0, strlen($avatarRoot));
- }
- return $user;
- }
- /**
- * 根据用户名和密码验证用户。
- * Identify user by account and password.
- *
- * @param string $account the user account
- * @param string $password the user password or auth hash
- * @access public
- * @return bool|object
- */
- public function identifyUser($account, $password)
- {
- $user = $this->dao->select('*')->from(TABLE_USER)->where('deleted')->eq('0')->andWhere('account')->eq($account)->fetch();
- if(!$user) return false;
- $passwordLength = strlen($password);
- if($passwordLength == 32)
- {
- $hash = $this->session->rand ? md5($user->password . $this->session->rand) : $user->password;
- if($password == $hash) return $user;
- }
- if($passwordLength == 40)
- {
- $lastTimestamp = is_numeric($user->last) ? $user->last : strtotime($user->last);
- $hash = sha1($user->account . $user->password . $lastTimestamp);
- if($password == $hash) return $user;
- }
- return md5($password) == $user->password ? $user : false;
- }
- /**
- * 检查是否需要修改密码。
- * Check if need to modify password.
- *
- * @param object $user
- * @param int $passwordStrength
- * @access public
- * @return object
- */
- public function checkNeedModifyPassword($user, $passwordStrength)
- {
- /* 如果开启了首次登录修改密码功能,检查是否是首次登录。*/
- /* If the modify password on first login feature is enabled, check if it's the first login. */
- if(!empty($this->config->safe->modifyPasswordFirstLogin))
- {
- $user->modifyPassword = $user->visits == 0;
- if($user->modifyPassword)
- {
- $user->modifyPasswordReason = 'modifyPasswordFirstLogin';
- return $user;
- }
- }
- /* 如果开启了修改弱口令密码功能,检查是否是弱口令。*/
- /* If the modify weak password feature is enabled, check if it's a weak password. */
- if(!empty($this->config->safe->changeWeak))
- {
- $user->modifyPassword = $this->loadModel('admin')->checkWeak($user);
- if($user->modifyPassword)
- {
- $user->modifyPasswordReason = 'weak';
- return $user;
- }
- }
- /* 如果开启了密码强度检查功能,检查密码是否满足强度要求。*/
- /* If the password strength feature is enabled, check if the password is strong enough. */
- if(!empty($this->config->safe->mode) && $this->app->moduleName == 'user' && $this->app->methodName == 'login')
- {
- $user->modifyPassword = $passwordStrength < $this->config->safe->mode;
- if($user->modifyPassword)
- {
- $user->modifyPasswordReason = 'passwordStrengthWeak';
- return $user;
- }
- }
- return $user;
- }
- /**
- * 根据 PHP 的 HTTP 认证验证用户。
- * Identify user by PHP HTTP auth.
- *
- * @access public
- * @return bool
- */
- public function identifyByPhpAuth()
- {
- $account = $this->server->php_auth_user;
- $password = $this->server->php_auth_pw;
- $user = $this->identify($account, $password);
- if(!$user) return false;
- $user->rights = $this->authorize($account);
- $user->groups = $this->getGroups($account);
- $user->view = $this->grantUserView($user->account, $user->rights['acls']);
- $this->session->set('user', $user);
- $this->app->user = $this->session->user;
- $this->loadModel('action')->create('user', $user->id, 'login');
- $this->loadModel('score')->create('user', 'login');
- $this->loadModel('common')->loadConfigFromDB();
- return true;
- }
- /**
- * 根据 Cookie 验证用户。
- * Identify user by cookie.
- *
- * @access public
- * @return bool
- */
- public function identifyByCookie()
- {
- $account = $this->cookie->za;
- $authHash = $this->cookie->zp;
- $user = $this->identify($account, $authHash, 3); // Set passwordStrength=MAX_PASSWORD_STRENGTH, don't check modifyPassword.
- if(!$user) return false;
- $user->rights = $this->authorize($account);
- $user->groups = $this->getGroups($account);
- $user->view = $this->grantUserView($user->account, $user->rights['acls']);
- $this->session->set('user', $user);
- $this->app->user = $this->session->user;
- $this->loadModel('action')->create('user', $user->id, 'login');
- $this->loadModel('score')->create('user', 'login');
- $this->loadModel('common')->loadConfigFromDB();
- $this->keepLogin($user);
- return true;
- }
- /**
- * 获取某用户的视图访问权限。
- * Get user acls.
- *
- * @param string $account
- * @access private
- * @return array
- */
- private function getUserAcls($account)
- {
- if($account == 'guest')
- {
- $acls = $this->dao->select('acl')->from(TABLE_GROUP)->where('name')->eq('guest')->fetch('acl');
- return !empty($acls) ? json_decode($acls, true) : array();
- }
- $groups = $this->dao->select('t1.acl, t1.project')->from(TABLE_GROUP)->alias('t1')
- ->leftJoin(TABLE_USERGROUP)->alias('t2')->on('t1.id=t2.`group`')
- ->where('t2.account')->eq($account)
- ->andWhere('t1.vision')->eq($this->config->vision)
- ->andWhere('t1.role')->ne('projectAdmin')
- ->andWhere('t1.role')->ne('limited')
- ->andWhere('t1.project')->eq(0)
- ->fetchAll();
- /* Init variables. */
- $acls = array('programs' => array(), 'projects' => array(), 'products' => array(), 'sprints' => array(), 'views' => array(), 'actions' => array());
- $programAllow = $projectAllow = $productAllow = $sprintAllow = $viewAllow = $actionAllow = false;
- /* Authorize by group. */
- foreach($groups as $group)
- {
- /* 只要有一个权限分组没有配置过视图权限,就代表所有视图都没有访问限制。 */
- if(empty($group->acl))
- {
- $programAllow = $projectAllow = $productAllow = $sprintAllow = $viewAllow = $actionAllow = true;
- break;
- }
- $acl = json_decode($group->acl, true);
- /* 只要有一个权限分组的某个配置为空,就代表该配置没有访问限制。 */
- if(empty($acl['programs'])) $programAllow = true;
- if(empty($acl['projects'])) $projectAllow = true;
- if(empty($acl['products'])) $productAllow = true;
- if(empty($acl['sprints'])) $sprintAllow = true;
- if(empty($acl['views'])) $viewAllow = true;
- if(!isset($acl['actions'])) $actionAllow = true;
- /* 将所有权限分组的视图访问限制合并。 */
- if(!$programAllow && !empty($acl['programs'])) $acls['programs'] = array_merge($acls['programs'], $acl['programs']);
- if(!$projectAllow && !empty($acl['projects'])) $acls['projects'] = array_merge($acls['projects'], $acl['projects']);
- if(!$productAllow && !empty($acl['products'])) $acls['products'] = array_merge($acls['products'], $acl['products']);
- if(!$sprintAllow && !empty($acl['sprints'])) $acls['sprints'] = array_merge($acls['sprints'], $acl['sprints']);
- if(!$actionAllow && !empty($acl['actions'])) $acls['actions'] = array_merge($acls['actions'], $acl['actions']);
- if(!$viewAllow && !empty($acl['views'])) $acls['views'] = array_merge($acls['views'], $acl['views']);
- }
- /* 只要有一个权限分组的某个配置为空,就代表该配置没有访问限制。 */
- if($programAllow) $acls['programs'] = array();
- if($projectAllow) $acls['projects'] = array();
- if($productAllow) $acls['products'] = array();
- if($sprintAllow) $acls['sprints'] = array();
- if($viewAllow) $acls['views'] = array();
- if($actionAllow) $acls['actions'] = array();
- if($actionAllow && empty($acls['actions'])) unset($acls['actions']);
- return $acls;
- }
- /**
- * 获取某个用户的权限。
- * Get user's rights.
- *
- * @param string $account
- * @access public
- * @return array the user rights.
- */
- public function authorize($account)
- {
- $account = filter_var($account, FILTER_UNSAFE_RAW);
- if(!$account) return array();
- $acls = $this->getUserAcls($account);
- if($account == 'guest')
- {
- $stmt = $this->dao->select('module, method')->from(TABLE_GROUP)->alias('t1')->leftJoin(TABLE_GROUPPRIV)->alias('t2')->on('t1.id = t2.`group`')->where('t1.name')->eq('guest')->query();
- }
- else
- {
- $stmt = $this->dao->select('module, method')->from(TABLE_GROUP)->alias('t1')
- ->leftJoin(TABLE_USERGROUP)->alias('t2')->on('t1.id = t2.`group`')
- ->leftJoin(TABLE_GROUPPRIV)->alias('t3')->on('t2.`group` = t3.`group`')
- ->where('t2.account')->eq($account)
- ->andWhere('t1.project')->eq(0)
- ->andWhere('t1.vision')->eq($this->config->vision)
- ->query();
- }
- if(!$stmt) return array('rights' => array(), 'acls' => $acls);
- /* 获取用户拥有的权限列表,而首页是大家都应该有的权限。 */
- $rights = array('index' => array('index' => 1), 'my' => array('index' => 1));
- while($row = $stmt->fetch(PDO::FETCH_ASSOC))
- {
- if($row['module'] && $row['method']) $rights[strtolower($row['module'])][strtolower($row['method'])] = true;
- }
- /* Get can manage projects by user. */
- $canManageProjects = $canManagePrograms = $canManageProducts = $canManageExecutions = '';
- if(!$this->app->upgrading)
- {
- $canManageObjects = $this->dao->select('programs,projects,products,executions')->from(TABLE_PROJECTADMIN)->where('account')->eq($account)->fetchAll();
- foreach($canManageObjects as $object)
- {
- if($object->projects) $canManageProjects .= $object->projects . ',';
- if($object->products) $canManageProducts .= $object->products . ',';
- if($object->programs) $canManagePrograms .= $object->programs . ',';
- if($object->executions) $canManageExecutions .= $object->executions . ',';
- }
- }
- return array('rights' => $rights, 'acls' => $acls, 'projects' => $canManageProjects, 'programs' => $canManagePrograms, 'products' => $canManageProducts, 'executions' => $canManageExecutions);
- }
- /**
- * 获取用户所属权限组、权限和视图,记录日志并发放登录积分。
- * Get user's groups, rights and views, save log and give login score.
- *
- * @param object $user
- * @param bool $addAction
- * @param bool $keepLogin
- * @access public
- * @return false|object
- */
- public function login($user, $addAction = true, $keepLogin = false)
- {
- if(empty($user->account)) return false;
- if($user->fails || $user->locked) $this->cleanLocked($user->account);
- /* 获取用户所属权限组、权限和视图,判断用户是否是管理员。*/
- /* Get user's groups, rights and views, and judge if the user is admin. */
- $user->rights = $this->authorize($user->account);
- $user->groups = $this->getGroups($user->account);
- $user->view = $this->grantUserView($user->account, $user->rights['acls'], $user->rights['projects']);
- $user->admin = strpos($this->app->company->admins, ",{$user->account},") !== false;
- $this->session->set('user', $user);
- $this->app->user = $this->session->user;
- /* 记录登录日志并发放积分。*/
- /* Save log and give login score. */
- if(isset($user->id) and $addAction) $this->loadModel('action')->create('user', $user->id, 'login');
- $this->loadModel('score')->create('user', 'login');
- /* 保持登录状态。*/
- /* Keep login. */
- if($keepLogin) $this->keepLogin($user);
- return $user;
- }
- /**
- * 保持用户的登录状态。
- * Keep user's login state.
- *
- * @param object $user
- * @access public
- * @return bool
- */
- public function keepLogin($user)
- {
- helper::setcookie('keepLogin', 'on');
- helper::setcookie('za', $user->account);
- helper::setcookie('zp', sha1($user->account . $user->password . $this->server->request_time));
- return true;
- }
- /**
- * 判断用户是否已经登录。
- * Check if the user has logged in.
- *
- * @access public
- * @return bool
- */
- public function isLogon()
- {
- $user = $this->session->user;
- return ($user && !empty($user->account) && $user->account != 'guest');
- }
- /**
- * 获取用户所属的权限组。
- * Get groups a user belongs to.
- *
- * @param string $account
- * @access public
- * @return array
- */
- public function getGroups($account)
- {
- return $this->dao->findByAccount($account)->from(TABLE_USERGROUP)->fields('`group`')->fetchPairs();
- }
- /**
- * 根据界面类型获取权限组。
- * Get groups by visions.
- *
- * @param string|array $visions
- * @access public
- * @return array
- */
- public function getGroupsByVisions($visions)
- {
- if(is_string($visions)) $visions = array_unique(array_filter(explode(',', $visions)));
- if(!$visions) return array();
- $groups = $this->dao->select('id, name, vision')->from(TABLE_GROUP)
- ->where('project')->eq(0)
- ->andWhere('role')->ne('projectAdmin')
- ->andWhere('vision')->in($visions)
- ->fetchAll('id');
- $visionCount = count($visions);
- $visionList = getVisions();
- foreach($groups as $id => $group)
- {
- $groups[$id] = $group->name;
- if($visionCount > 1 && !empty($visionList[$group->vision])) $groups[$id] = $visionList[$group->vision] . ' / ' . $group->name;
- }
- return $groups;
- }
- /**
- * 获取某个用户参与的项目。
- * Get the projects that a user participated in.
- *
- * @param string $account
- * @param string $status
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getProjects($account, $status = 'all', $orderBy = 'id_desc', $pager = null)
- {
- $this->loadModel('project');
- $projects = $this->userTao->fetchProjects($account, $status, $orderBy, $pager);
- if(!$projects) return array();
- $projectStoryCountAndEstimate = $this->userTao->fetchProjectStoryCountAndEstimate(array_keys($projects));
- $projectExecutionCount = $this->userTao->fetchProjectExecutionCount(array_keys($projects));
- foreach($projects as $project)
- {
- /* Judge whether the project is delayed. */
- if($project->status != 'done' && $project->status != 'closed' && $project->status != 'suspended')
- {
- $delay = helper::diffDate(helper::today(), $project->end);
- if($delay > 0) $project->delay = $delay;
- }
- $projectStory = zget($projectStoryCountAndEstimate, $project->id, '');
- $project->storyPoints = $projectStory ? round($projectStory->estimate, 1) : 0;
- $project->storyCount = $projectStory ? $projectStory->count : 0;
- $project->executionCount = zget($projectExecutionCount, $project->id, 0);
- }
- if(in_array($this->config->edition, array('max', 'ipd'))) $projects = $this->project->countDeliverable($projects, 'project');
- return $projects;
- }
- /**
- * 获取某个用户参与的执行。
- * Get the executions that a user participated in.
- *
- * @param string $account
- * @param string $status
- * @param string $orderBy
- * @param object $pager
- * @access public
- * @return array
- */
- public function getExecutions($account, $status = 'all', $orderBy = 'id_desc', $pager = null)
- {
- $executions = $this->userTao->fetchExecutions($account, $status, $orderBy, $pager);
- if(!$executions) return array();
- $projectIdList = array_map(function($execution){return $execution->project;}, $executions);
- $projectPairs = $this->loadModel('project')->getPairsByIdList($projectIdList);
- $taskCountList = $this->userTao->fetchExecutionTaskCount($account, array_keys($executions));
- foreach($executions as $execution)
- {
- /* Judge whether the execution is delayed. */
- if($execution->status != 'done' && $execution->status != 'closed' && $execution->status != 'suspended')
- {
- $delay = helper::diffDate(helper::today(), $execution->end);
- if($delay > 0) $execution->delay = $delay;
- }
- $execution->projectName = zget($projectPairs, $execution->project, '');
- $execution->assignedToMeTasks = zget($taskCountList, $execution->id, 0);
- }
- return $executions;
- }
- /**
- * 登录失败次数加 1。
- * The number of failed login attempts is increased by 1.
- *
- * @param string $account
- * @access public
- * @return int
- */
- public function failPlus($account)
- {
- if(!validater::checkAccount($account)) return 0;
- /* Save session fails. */
- $sessionFails = (int)$this->session->loginFails;
- $sessionFails += 1;
- $this->session->set('loginFails', $sessionFails);
- if($sessionFails >= $this->config->user->failTimes) $this->session->set("{$account}.loginLocked", date('Y-m-d H:i:s'));
- $user = $this->dao->select('fails')->from(TABLE_USER)->where('account')->eq($account)->fetch();
- if(empty($user)) return 0;
- $fails = $user->fails;
- $fails ++;
- if($fails < $this->config->user->failTimes)
- {
- $this->dao->update(TABLE_USER)->set('fails')->eq($fails)->set('locked = NULL')->where('account')->eq($account)->exec();
- return $fails;
- }
- $this->dao->update(TABLE_USER)->set('fails')->eq(0)->set('locked')->eq(date('Y-m-d H:i:s'))->where('account')->eq($account)->exec();
- return $fails;
- }
- /**
- * 检查用户是否被锁定。
- * Check whether the user is locked.
- *
- * @param string $account
- * @access public
- * @return bool
- */
- public function checkLocked($account)
- {
- $user = $this->dao->select('locked')->from(TABLE_USER)->where('account')->eq($account)->fetch();
- if(empty($user) || empty($user->locked)) return false;
- if($this->session->{"{$account}.loginLocked"} && (time() - strtotime($this->session->{"{$account}.loginLocked"})) <= $this->config->user->lockMinutes * 60) return true;
- if((time() - strtotime($user->locked)) > $this->config->user->lockMinutes * 60) return false;
- return true;
- }
- /**
- * 解锁被锁定的用户。
- * Unlock the locked user.
- *
- * @param string $account
- * @access public
- * @return bool
- */
- public function cleanLocked($account)
- {
- $this->dao->update(TABLE_USER)->set('fails')->eq(0)->set('locked = NULL')->where('account')->eq($account)->exec();
- unset($_SESSION['loginFails']);
- unset($_SESSION["{$account}.loginLocked"]);
- return !dao::isError();
- }
- /**
- * 解除禅道账号和 ZDOO 账号的绑定。
- * Unbind ZDOO account and ZenTao account.
- *
- * @param string $account
- * @access public
- * @return bool
- */
- public function unbind($account)
- {
- $this->dao->update(TABLE_USER)->set('ranzhi')->eq('')->where('account')->eq($account)->exec();
- return !dao::isError();
- }
- /**
- * 上传头像。
- * Upload avatar.
- *
- * @access public
- * @return array
- */
- public function uploadAvatar()
- {
- $uploadResult = $this->loadModel('file')->saveUpload('avatar');
- if(!$uploadResult) return array('result' => 'fail', 'message' => $this->lang->fail);
- $fileIdList = array_keys($uploadResult);
- $file = $this->file->getByID(end($fileIdList));
- $imageExtensions = $this->config->file->imageExtensions;
- if(!in_array($file->extension, $imageExtensions)) return array('result' => 'fail', 'message' => sprintf($this->lang->user->error->uploadAvatar, implode(', ', $imageExtensions)));
- return array('result' => 'success', 'message' => '', 'fileID' => $file->id, 'locate' => helper::createLink('user', 'cropavatar', "image={$file->id}"));
- }
- /**
- * 获取某个用户可以查看的联系人列表。
- * Get the contact list of a user.
- *
- * @param string $account
- * @param string $mode pairs|list
- * @access public
- * @return array
- */
- public function getContactLists($account = '', $mode = 'pairs')
- {
- if(!$account) $account = $this->app->user->account;
- $this->dao->select('*')->from(TABLE_USERCONTACT)
- ->where('account')->eq($account)
- ->orWhere('public')->eq(1)
- ->orderBy('public, id_desc');
- if($mode == 'pairs') return $this->dao->fetchPairs('id', 'listName');
- return $this->dao->fetchAll();
- }
- /**
- * 获取拥有迭代访问权限的用户列表。
- * Get users who have access to the parent stage.
- *
- * @param int $stageID
- * @access public
- * @return array
- */
- public function getParentStageAuthedUsers($stageID = 0)
- {
- return $this->dao->select('account')->from(TABLE_USERVIEW)->where("FIND_IN_SET({$stageID}, sprints)")->fetchPairs();
- }
- /**
- * 根据 id 获取一个联系人列表。
- * Get a contact list by id.
- *
- * @param int $listID
- * @access public
- * @return object|false
- */
- public function getContactListByID($listID)
- {
- return $this->dao->select('*')->from(TABLE_USERCONTACT)->where('id')->eq($listID)->fetch();
- }
- /**
- * 创建一个联系人列表。
- * Create a contact list.
- *
- * @param object $userContact
- * @access public
- * @return bool
- */
- public function createContactList($userContact)
- {
- $this->dao->insert(TABLE_USERCONTACT)->data($userContact)
- ->batchCheck('listName,userList', 'notempty')
- ->check('listName', 'unique', "account = '{$userContact->account}'")
- ->autoCheck()
- ->exec();
- return !dao::isError();
- }
- /**
- * 更新一个联系人列表。
- * Update a contact list.
- *
- * @param object $userContact
- * @access public
- * @return bool
- */
- public function updateContactList($userContact)
- {
- $this->dao->update(TABLE_USERCONTACT)->data($userContact)
- ->batchCheck('listName,userList', 'notempty')
- ->check('listName', 'unique', "id != '{$userContact->id}' AND account = '{$userContact->account}'")
- ->autoCheck()
- ->where('id')->eq($userContact->id)
- ->exec();
- return !dao::isError();
- }
- /**
- * 删除一个联系人列表。
- * Delete a contact list.
- *
- * @param int $listID
- * @access public
- * @return bool
- */
- public function deleteContactList($listID)
- {
- $this->dao->delete()->from(TABLE_USERCONTACT)->where('id')->eq($listID)->exec();
- return !dao::isError();
- }
- /**
- * 获取弱密码用户。
- * Get weak users.
- *
- * @access public
- * @return array
- */
- public function getWeakUsers()
- {
- $weaks = array();
- foreach(explode(',', $this->config->safe->weak) as $weak)
- {
- if($weak) $weaks[$weak] = md5(trim($weak));
- }
- $weakUsers = array();
- $users = $this->dao->select('*')->from(TABLE_USER)->where('deleted')->eq('0')->fetchAll();
- foreach($users as $user)
- {
- if(isset($weaks[$user->password]) || in_array($user->password, $weaks))
- {
- $user->weakReason = 'weak';
- $weakUsers[] = $user;
- continue;
- }
- foreach(array('account', 'phone', 'mobile', 'birthday') as $field)
- {
- if(empty($user->$field)) continue;
- if($user->password == $user->$field || $user->password == md5($user->$field))
- {
- $user->weakReason = $field;
- $weakUsers[] = $user;
- break;
- }
- }
- }
- return $weakUsers;
- }
- /**
- * 计算密码强度。
- * Compute password strength.
- *
- * @param string $password
- * @access public
- * @return int
- */
- public function computePasswordStrength($password)
- {
- $length = strlen($password);
- if($length == 0) return 0;
- $complexity = array();
- $chars = str_split($password);
- foreach($chars as $letter)
- {
- $asc = ord($letter);
- if($asc >= 48 && $asc <= 57)
- {
- $complexity[0] = 1;
- }
- elseif($asc >= 65 && $asc <= 90)
- {
- $complexity[1] = 2;
- }
- elseif($asc >= 97 && $asc <= 122)
- {
- $complexity[2] = 4;
- }
- else
- {
- $complexity[3] = 8;
- }
- }
- $sumComplexity = array_sum($complexity);
- if($sumComplexity == 15 && $length >= 10) return 2;
- if(($sumComplexity == 7 || $sumComplexity == 15) && $length >= 6) return 1;
- return 0;
- }
- /**
- * 初始化访问权限所属的数据。
- * Init user view objects.
- *
- * @param string $account
- * @access private
- * @return array
- */
- private function initViewObjects($account)
- {
- $this->loadModel('project');
- static $allProducts, $allProjects, $allPrograms, $allSprints, $teams, $whiteList, $stakeholders;
- if(!$allProducts) $allProducts = $this->loadModel('product')->getListByAcl('private');
- if(!$allProjects) $allProjects = $this->project->getListByAclAndType('private,program', 'project');
- if(!$allPrograms) $allPrograms = $this->project->getListByAclAndType('private,program', 'program');
- if(!$allSprints) $allSprints = $this->project->getListByAclAndType('private', 'sprint,stage,kanban');
- if(empty($teams[$account]))
- {
- $teams[$account] = [];
- $teamList = $this->project->getTeamListByType('project,execution', $account);
- foreach($teamList as $team) $teams[$account][$team->type][$team->root][$team->account] = $team->account;
- }
- /* Get white list. */
- if(empty($whiteList[$account]))
- {
- $whiteList[$account] = [];
- $aclList = $this->project->getAclListByObjectType('program,project,sprint,product', $account);
- foreach($aclList as $acl) $whiteList[$account][$acl->objectType][$acl->objectID][$acl->account] = $acl->account;
- }
- /* Get stakeholders. */
- if(empty($stakeholders[$account]))
- {
- $stakeholders[$account] = [];
- $cachedHolders = $this->dao->select('objectID, objectType, user')->from(TABLE_STAKEHOLDER)->where('deleted')->eq('0')->andWhere('user')->eq($account)->fetchAll();
- foreach($cachedHolders as $holder) $stakeholders[$account][$holder->objectType][$holder->objectID][$holder->user] = $holder->user;
- }
- return array($allProducts, $allProjects, $allPrograms, $allSprints, $teams[$account], $whiteList[$account], $stakeholders[$account]);
- }
- /**
- * 获取用户的可访问项目集。
- * Get program user view.
- *
- * @param string $account
- * @param array $allPrograms
- * @param array $manageObjects
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $programStakeholderGroup
- * @access private
- * @return string
- */
- private function getProgramView($account, $allPrograms, $manageObjects, $stakeholders, $whiteList, $programStakeholderGroup)
- {
- $programView = '';
- if(!empty($manageObjects['programs']['isAdmin']))
- {
- $programView = implode(',', array_keys($allPrograms));
- }
- else
- {
- $programs = array();
- $managePrograms = isset($manageObjects['programs']['list']) ? $manageObjects['programs']['list'] : '';
- foreach($allPrograms as $programID => $program)
- {
- /* 如果是某个项目集的干系人,也可以访问该项目集。 */
- $programStakeholders = !empty($stakeholders['program'][$programID]) ? $stakeholders['program'][$programID] : array();
- if($program->acl == 'program') $programStakeholders += zget($programStakeholderGroup, $programID, array());
- /* 如果是某个项目集的白名单用户,也可以访问该项目集。 */
- $programWhiteList = !empty($whiteList['program'][$programID]) ? $whiteList['program'][$programID] : array();
- if($this->checkProgramPriv($program, $account, $programStakeholders, $programWhiteList)) $programs[$programID] = $programID;
- /* 如果有某个项目集的管理权限,也可以访问该项目集。 */
- if(strpos(",$managePrograms,", ",$programID,") !== false) $programs[$programID] = $programID;
- }
- $programView = implode(',', $programs);
- }
- return $programView;
- }
- /**
- * 获取用户的可访问产品。
- * Get product user view.
- *
- * @param string $account
- * @param array $allProducts
- * @param array $manageObjects
- * @param array $whiteList
- * @access private
- * @return string
- */
- private function getProductView($account, $allProducts, $manageObjects, $whiteList)
- {
- $productView = '';
- if(!empty($manageObjects['products']['isAdmin']))
- {
- $productView = implode(',', array_keys($allProducts));
- }
- else
- {
- $products = array();
- $manageProducts = isset($manageObjects['products']['list']) ? $manageObjects['products']['list'] : '';
- list($productTeams, $productStakeholders) = $this->getProductMembers($allProducts, $account);
- foreach($allProducts as $productID => $product)
- {
- /* 根据团队、干系人、白名单判断是否可以访问该产品。 */
- $productTeam = zget($productTeams, $productID, array());
- $productStakeholder = zget($productStakeholders, $productID, array());
- $productWhiteList = !empty($whiteList['product'][$productID]) ? $whiteList['product'][$productID] : array();
- if($this->checkProductPriv($product, $account, $productTeam, $productStakeholder, $productWhiteList)) $products[$productID] = $productID;
- /* 如果有某个产品的管理权限,也可以访问该产品。 */
- if(strpos(",$manageProducts,", ",$productID,") !== false) $products[$productID] = $productID;
- }
- $productView = implode(',', $products);
- }
- return $productView;
- }
- /**
- * 获取用户的可访问项目。
- * Get project user view.
- *
- * @param string $account
- * @param array $allProjects
- * @param array $manageObjects
- * @param array $teams
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $projectStakeholderGroup
- * @access private
- * @return string
- */
- private function getProjectView($account, $allProjects, $manageObjects, $teams, $stakeholders, $whiteList, $projectStakeholderGroup)
- {
- $projectView = '';
- if(!empty($manageObjects['projects']['isAdmin']))
- {
- $projectView = implode(',', array_keys($allProjects));
- }
- else
- {
- $projects = array();
- $manageProjects = isset($manageObjects['projects']['list']) ? $manageObjects['projects']['list'] : '';
- foreach($allProjects as $projectID => $project)
- {
- /* 根据团队、干系人、白名单判断是否可以访问该项目。 */
- $projectTeams = !empty($teams['project'][$projectID]) ? $teams['project'][$projectID] : array();
- $projectStakeholders = !empty($stakeholders['project'][$projectID]) ? $stakeholders['project'][$projectID] : array();
- $projectWhiteList = !empty($whiteList['project'][$projectID]) ? $whiteList['project'][$projectID] : array();
- if($project->acl == 'program') $projectStakeholders += zget($projectStakeholderGroup, $projectID, array());
- if($this->checkProjectPriv($project, $account, $projectStakeholders, $projectTeams, $projectWhiteList)) $projects[$projectID] = $projectID;
- /* 如果有某个项目管理权限,也可以访问该项目。 */
- if(strpos(",$manageProjects,", ",$projectID,") !== false) $projects[$projectID] = $projectID;
- }
- $projectView = implode(',', $projects);
- }
- return $projectView;
- }
- /**
- * 获取用户的可访问迭代。
- * Get sprint user view.
- *
- * @param string $account
- * @param array $allSprints
- * @param array $manageObjects
- * @param array $teams
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $executionStakeholderGroup
- * @access private
- * @return string
- */
- private function getSprintView($account, $allSprints, $manageObjects, $teams, $stakeholders, $whiteList, $executionStakeholderGroup)
- {
- $sprintView = '';
- if(!empty($manageObjects['executions']['isAdmin']))
- {
- $sprintView = implode(',', array_keys($allSprints));
- }
- else
- {
- $sprints = array();
- $manageExecutions = isset($manageObjects['executions']['list']) ? $manageObjects['executions']['list'] : '';
- foreach($allSprints as $sprintID => $sprint)
- {
- /* 根据团队、干系人、白名单判断是否可以访问该迭代。 */
- $sprintTeams = !empty($teams['execution'][$sprintID]) ? $teams['execution'][$sprintID] : array();
- $sprintStakeholders = !empty($stakeholders['execution'][$sprintID]) ? $stakeholders['execution'][$sprintID] : array();
- $sprintWhiteList = !empty($whiteList['sprint'][$sprintID]) ? $whiteList['sprint'][$sprintID] : array();
- if($sprint->acl == 'private') $sprintStakeholders += zget($executionStakeholderGroup, $sprintID, array());
- if($this->checkProjectPriv($sprint, $account, $sprintStakeholders, $sprintTeams, $sprintWhiteList)) $sprints[$sprintID] = $sprintID;
- /* 如果有某个迭代管理权限,也可以访问该迭代。 */
- if(strpos(",$manageExecutions,", ",$sprintID,") !== false) $sprints[$sprintID] = $sprintID;
- }
- $sprintView = implode(',', $sprints);
- }
- return $sprintView;
- }
- /**
- * 按照类型分组获取用户管理的对象。
- * Get management objects by type grouping.
- *
- * @param string $account
- * @access private
- * @return array
- */
- private function getManageListGroupByType($account)
- {
- $manageObjects = array();
- $projectAdmins = $this->dao->select('`group`,programs,products,projects,executions')->from(TABLE_PROJECTADMIN)->where('account')->eq($account)->fetchAll('group');
- foreach($projectAdmins as $projectAdmin)
- {
- foreach($projectAdmin as $key => $value)
- {
- if(!isset($manageObjects[$key]['list'])) $manageObjects[$key]['list'] = '';
- if($value == 'all')
- {
- $manageObjects[$key]['isAdmin'] = 1;
- }
- else if($value)
- {
- $manageObjects[$key]['list'] .= $value . ',';
- }
- }
- }
- return $manageObjects;
- }
- /**
- * 获取用户的可访问对象。
- * Compute user view.
- *
- * @param string $account
- * @param bool $force 是否重新生成
- * @access public
- * @return object
- */
- public function computeUserView($account = '', $force = false)
- {
- if(empty($account))
- {
- $account = $this->session->user->account;
- if(empty($account))
- {
- $userView = new stdclass();
- $userView->products = $userView->programs = $userView->projects = $userView->sprints = '';
- return $userView;
- }
- }
- $oldUserView = $this->dao->select('*')->from(TABLE_USERVIEW)->where('account')->eq($account)->fetch();
- if(!$force)
- {
- $userviewUpdateTime = $this->config->userview->updateTime ?? 0; // 当前用户访问权限的更新时间。
- $relatedTablesUpdateTime = $this->config->userview->relatedTablesUpdateTime ?? 0; // 访问权限相关表的更新时间。
- $force = empty($userviewUpdateTime) || empty($relatedTablesUpdateTime) || $userviewUpdateTime <= $relatedTablesUpdateTime;
- }
- if(!$force)
- {
- if($oldUserView) return $oldUserView;
- $userView = new stdclass();
- $userView->products = $userView->programs = $userView->projects = $userView->sprints = '';
- return $userView;
- }
- /* Init objects. */
- list($allProducts, $allProjects, $allPrograms, $allSprints, $teams, $whiteList, $stakeholders) = $this->initViewObjects($account);
- /* Init user view. */
- $userView = new stdclass();
- $userView->account = $account;
- $isAdmin = strpos($this->app->company->admins, ',' . $account . ',') !== false;
- if($isAdmin)
- {
- $userView->programs = implode(',', array_keys($allPrograms));
- $userView->products = implode(',', array_keys($allProducts));
- $userView->projects = implode(',', array_keys($allProjects));
- $userView->sprints = implode(',', array_keys($allSprints));
- }
- else
- {
- /* Compute parent stakeholders. */
- $this->loadModel('stakeholder');
- $programStakeholderGroup = $this->stakeholder->getParentStakeholderGroup(array_keys($allPrograms));
- $projectStakeholderGroup = $this->stakeholder->getParentStakeholderGroup(array_keys($allProjects));
- $executionStakeholderGroup = $this->stakeholder->getParentStakeholderGroup(array_keys($allSprints));
- /* 按照类型分组获取当前用户所拥有的的项目管理权限。 */
- $manageObjects = $this->getManageListGroupByType($account);
- /* 分别获取各类型的可浏览ID。 */
- $userView->programs = $this->getProgramView($account, $allPrograms, $manageObjects, $stakeholders, $whiteList, $programStakeholderGroup);
- $userView->products = $this->getProductView($account, $allProducts, $manageObjects, $whiteList);
- $userView->projects = $this->getProjectView($account, $allProjects, $manageObjects, $teams, $stakeholders, $whiteList, $projectStakeholderGroup);
- $userView->sprints = $this->getSprintView($account, $allSprints, $manageObjects, $teams, $stakeholders, $whiteList, $executionStakeholderGroup);
- }
- /* 更新访问权限表。 */
- $this->dao->begin();
- if(empty($oldUserView))
- {
- $this->dao->insert(TABLE_USERVIEW)->data($userView)->exec();
- }
- else
- {
- $this->dao->update(TABLE_USERVIEW)->data($userView)->where('account')->eq($account)->exec();
- }
- $this->loadModel('setting')->setItem("$account|common|userview|updateTime", time(), '|');
- $this->dao->commit();
- return $userView;
- }
- /**
- * 获取产品关联的项目集干系人。
- * Get program stakeholder.
- *
- * @param array $programProduct
- * @access private
- * @return array
- */
- private function getProgramStakeholder($programProduct)
- {
- $stakeholderGroups = array();
- $stmt = $this->dao->select('objectID,user')->from(TABLE_STAKEHOLDER)
- ->where('objectType')->eq('program')
- ->andWhere('objectID')->in(array_keys($programProduct))
- ->query();
- while($programStakeholder = $stmt->fetch())
- {
- $productIDList = zget($programProduct, $programStakeholder->objectID, array());
- foreach($productIDList as $productID) $stakeholderGroups[$productID][$programStakeholder->user] = $programStakeholder->user;
- }
- $programOwners = $this->mao->select('id,PM')->from(TABLE_PROGRAM)
- ->where('type')->eq('program')
- ->andWhere('id')->in(array_keys($programProduct))
- ->fetchAll();
- foreach($programOwners as $programOwner)
- {
- $productIDList = zget($programProduct, $programOwner->id, array());
- foreach($productIDList as $productID) $stakeholderGroups[$productID][$programOwner->PM] = $programOwner->PM;
- }
- return $stakeholderGroups;
- }
- /**
- * 获取产品的所属团队和干系人。
- * Get product teams and stakeholders.
- *
- * @param array $allProducts
- * @param string $account
- * @access protected
- * @return array
- */
- protected function getProductMembers($allProducts, $account = '')
- {
- /* Get product and project relation. */
- $projectProducts = array();
- $stmt = $this->dao->select('t1.project, t1.product')->from(TABLE_PROJECTPRODUCT)->alias('t1')
- ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
- ->where('t1.product')->in(array_keys($allProducts))
- ->andWhere('t2.deleted')->eq('0')
- ->query();
- while($projectProduct = $stmt->fetch()) $projectProducts[$projectProduct->project][$projectProduct->product] = $projectProduct->product;
- /* Get linked projects stakeholders. */
- $stmt = $this->dao->select('objectID,user')->from(TABLE_STAKEHOLDER)
- ->where('objectType')->eq('project')
- ->andWhere('objectID')->in(array_keys($projectProducts))
- ->andWhere('deleted')->eq(0)
- ->query();
- $stakeholderGroups = array();
- while($stakeholder = $stmt->fetch())
- {
- $productIdList = zget($projectProducts, $stakeholder->objectID, array());
- foreach($productIdList as $productID) $stakeholderGroups[$productID][$stakeholder->user] = $stakeholder->user;
- }
- /* Get linked programs stakeholders. */
- $programProduct = array();
- foreach($allProducts as $product)
- {
- if($product->program) $programProduct[$product->program][$product->id] = $product->id;
- }
- if($programProduct)
- {
- $programStakeholderGroup = $this->getProgramStakeholder($programProduct);
- foreach($programStakeholderGroup as $productID => $stakeholders)
- {
- if(isset($stakeholderGroups[$productID]))
- {
- $stakeholderGroups[$productID] = arrayUnion($stakeholderGroups[$productID], $stakeholders);
- }
- else
- {
- $stakeholderGroups[$productID] = $stakeholders;
- }
- }
- }
- /* Get linked projects teams. */
- $teamsGroup = array();
- $teamList = $this->loadModel('project')->getTeamListByType('project', $account);
- foreach($teamList as $team)
- {
- if(!isset($projectProducts[$team->root])) continue;
- $productIdList = zget($projectProducts, $team->root, array());
- foreach($productIdList as $productID) $teamsGroup[$productID][$team->account] = $team->account;
- }
- return array($teamsGroup, $stakeholderGroups);
- }
- /**
- * 组装最终的用户可访问权限。
- * Grant user view.
- *
- * @param string $account
- * @param array $acls
- * @param string $projects 此人管理的项目列表
- * @access public
- * @return object
- */
- public function grantUserView($account = '', $acls = array(), $projects = '')
- {
- if(empty($account)) $account = $this->session->user->account;
- if(empty($account)) return new stdclass();
- if(empty($acls) && !empty($this->session->user->rights['acls'])) $acls = $this->session->user->rights['acls'];
- if(empty($projects) && !empty($this->session->user->rights['projects'])) $projects = $this->session->user->rights['projects'];
- $userView = $this->computeUserView($account);
- /* Get opened projects, programs, products and set it to userview. */
- $openedProducts = array_keys($this->loadModel('product')->getListByAcl('open'));
- $openedPrograms = array_keys($this->loadModel('project')->getListByAclAndType('open', 'program'));
- $openedProjects = array_keys($this->project->getListByAclAndType('open', 'project'));
- $userView->products = rtrim($userView->products, ',') . ',' . implode(',', $openedProducts);
- $userView->programs = rtrim($userView->programs, ',') . ',' . implode(',', $openedPrograms);
- $userView->projects = rtrim($userView->projects, ',') . ',' . implode(',', $openedProjects);
- /* 合并用户视图权限到用户访问权限。 */
- $userView = $this->mergeAclsToUserView($account, $userView, $acls, $projects);
- $userView->products = trim($userView->products, ',');
- $userView->programs = trim($userView->programs, ',');
- $userView->projects = trim($userView->projects, ',');
- $userView->sprints = trim($userView->sprints, ',');
- return $userView;
- }
- /**
- * 合并用户视图权限到用户访问权限。
- * Merge acls to userView.
- *
- * @param string $account
- * @param object $userView
- * @param array $acls
- * @param string $projects
- * @access private
- * @return object
- */
- private function mergeAclsToUserView($account, $userView, $acls, $projects)
- {
- if(isset($_SESSION['user']->admin)) $isAdmin = $this->session->user->admin;
- if(!isset($isAdmin)) $isAdmin = strpos($this->app->company->admins, ",{$account},") !== false;
- /* 权限分组-视野维护的优先级最高,所以这里进行了替换操作。*/
- /* View management has the highest priority, so there is a substitution. */
- if(!empty($acls['programs']) && !$isAdmin) $userView->programs = implode(',', $acls['programs']);
- if(!empty($acls['products']) && !$isAdmin) $userView->products = implode(',', $acls['products']);
- if(!empty($acls['sprints']) && !$isAdmin) $userView->sprints = implode(',', $acls['sprints']);
- if(!empty($acls['projects']) && !$isAdmin)
- {
- /* If is project admin, set projectID to userview. */
- if($projects) $acls['projects'] = array_merge($acls['projects'], explode(',', $projects));
- $userView->projects = implode(',', $acls['projects']);
- }
- /* 可以看到项目,就能看到项目下公开的迭代。 */
- /* Set opened sprints and stages into userview. */
- $openedSprints = $this->loadModel('project')->getListByAclAndType('open', 'sprint,stage,kanban');
- $openedSprints = array_filter(array_map(function($sprint) use ($userView) { if(strpos(",{$userView->projects},", ",{$sprint->project},") !== false) return $sprint->id; }, $openedSprints));
- $userView->sprints = rtrim($userView->sprints, ',') . ',' . implode(',', $openedSprints);
- $canViewSprints = $this->dao->select('executions')->from(TABLE_PROJECTADMIN)->where('account')->eq($account)->fetch('executions');
- if($canViewSprints != 'all') $userView->sprints .= ',' . $canViewSprints;
- return $userView;
- }
- /**
- * 更新某个对象下的用户可访问视图。
- * Update user view by object type.
- *
- * @param array $objectIDList
- * @param string $objectType
- * @param array $users
- * @access public
- * @return bool
- */
- public function updateUserView($objectIDList, $objectType, $users = array())
- {
- if($objectType == 'program') return $this->updateProgramView($objectIDList, $users);
- if($objectType == 'product') return $this->updateProductView($objectIDList, $users);
- if($objectType == 'project') return $this->updateProjectView($objectIDList, $users);
- if($objectType == 'sprint') return $this->updateSprintView($objectIDList, $users);
- return false;
- }
- /**
- * 更新项目集下的用户访问视图。
- * Update program user view.
- *
- * @param array $programIDList
- * @param array $users
- * @access private
- * @return bool
- */
- public function updateProgramView($programIDList, $users)
- {
- $programs = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->in($programIDList)->andWhere('acl')->ne('open')->fetchAll('id');
- if(empty($programs)) return false;
- $stakeholderGroup = $this->loadModel('stakeholder')->getStakeholderGroup($programIDList); // Get self stakeholders.
- $parentStakeholderGroup = $this->stakeholder->getParentStakeholderGroup($programIDList); // Get all parent program and subprogram relation.
- $parentPMGroup = $this->loadModel('program')->getParentPM($programIDList); // Get all parent program and subprogram relation.
- $programAdmins = $this->loadModel('group')->getAdmins($programIDList, 'programs'); // Get programs's admins.
- $stmt = $this->dao->select('objectID,account')->from(TABLE_ACL)->where('objectType')->eq('program')->andWhere('objectID')->in($programIDList)->query();
- $whiteListGroup = array();
- while($whiteList = $stmt->fetch()) $whiteListGroup[$whiteList->objectID][$whiteList->account] = $whiteList->account;
- $authedUsers = $users;
- /* 如果没传users参数,则获取项目集关联的所有人。*/
- if(empty($users)) $authedUsers += $this->getObjectsAuthedUsers($programs, 'program', $stakeholderGroup, array(), $whiteListGroup, $programAdmins, $parentStakeholderGroup, $parentPMGroup);
- $userViews = $this->dao->select("account,programs")->from(TABLE_USERVIEW)->where('account')->in($authedUsers)->fetchPairs('account', 'programs');
- /* Judge auth and update view. */
- foreach(array_filter($authedUsers) as $account)
- {
- $view = isset($userViews[$account]) ? $userViews[$account] : '';
- $latestView = $view;
- foreach($programs as $program)
- {
- $latestView = $this->getLatestUserView($account, $latestView, $program, 'program', $stakeholderGroup, array(), $whiteListGroup, $programAdmins, $parentStakeholderGroup, $parentPMGroup);
- }
- if($view != $latestView)
- {
- if(!isset($userViews[$account]))
- {
- $userView = new stdclass();
- $userView->account = $account;
- $userView->programs = $latestView;
- $userView->products = $userView->projects = $userView->sprints = '';
- $this->dao->insert(TABLE_USERVIEW)->data($userView)->exec();
- }
- else
- {
- $this->dao->update(TABLE_USERVIEW)->set('programs')->eq($latestView)->where('account')->eq($account)->exec();
- }
- }
- }
- return true;
- }
- /**
- * 更新项目下的用户访问视图。
- * Update project view.
- *
- * @param array $projectIDList
- * @param array $users
- * @access private
- * @return bool
- */
- public function updateProjectView($projectIDList, $users)
- {
- $projects = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->in($projectIDList)->andWhere('acl')->ne('open')->fetchAll('id');
- if(empty($projects)) return false;
- /* Get team group. */
- $stmt = $this->dao->select('root,account')->from(TABLE_TEAM)->where('type')->eq('project')->andWhere('root')->in($projectIDList)->andWhere('root')->ne(0)->query();
- $teamsGroup = array();
- while($team = $stmt->fetch()) $teamsGroup[$team->root][$team->account] = $team->account;
- /* Get white list group. */
- $stmt = $this->dao->select('objectID,account')->from(TABLE_ACL)->where('objectType')->eq('project')->andWhere('objectID')->in($projectIDList)->query();
- $whiteListGroup = array();
- while($whiteList = $stmt->fetch()) $whiteListGroup[$whiteList->objectID][$whiteList->account] = $whiteList->account;
- $stakeholderGroup = $this->loadModel('stakeholder')->getStakeholderGroup($projectIDList); // Get self stakeholders.
- $parentStakeholderGroup = $this->stakeholder->getParentStakeholderGroup($projectIDList); // Get all parent program and subprogram relation.
- $projectAdmins = $this->loadModel('group')->getAdmins($projectIDList, 'projects'); // Get projects's admins.
- /* Get auth users. */
- $authedUsers = $users;
- /* 如果没传users参数,则获取项目关联的所有人。*/
- if(empty($users)) $authedUsers += $this->getObjectsAuthedUsers($projects, 'project', $stakeholderGroup, $teamsGroup, $whiteListGroup, $projectAdmins, $parentStakeholderGroup, array());
- /* Get all projects user view. */
- $userViews = $this->dao->select("account,projects")->from(TABLE_USERVIEW)->where('account')->in($authedUsers)->fetchPairs('account', 'projects');
- /* Judge auth and update view. */
- foreach(array_filter($authedUsers) as $account)
- {
- $view = isset($userViews[$account]) ? $userViews[$account] : '';
- $latestView = $view;
- foreach($projects as $project)
- {
- $latestView = $this->getLatestUserView($account, $latestView, $project, 'project', $stakeholderGroup, $teamsGroup, $whiteListGroup, $projectAdmins, $parentStakeholderGroup, array());
- }
- if($view != $latestView)
- {
- if(!isset($userViews[$account]))
- {
- $userView = new stdclass();
- $userView->account = $account;
- $userView->projects = $latestView;
- $userView->products = $userView->programs = $userView->sprints = '';
- $this->dao->insert(TABLE_USERVIEW)->data($userView)->exec();
- }
- else
- {
- $this->dao->update(TABLE_USERVIEW)->set('projects')->eq($latestView)->where('account')->eq($account)->exec();
- }
- }
- }
- return true;
- }
- /**
- * 更新产品下的用户访问视图。
- * Update product user view.
- *
- * @param array $productIDList
- * @param array $user
- * @access private
- * @return bool
- * @param mixed[] $users
- */
- public function updateProductView($productIDList, $users)
- {
- $products = $this->dao->select('*')->from(TABLE_PRODUCT)->where('id')->in($productIDList)->andWhere('acl')->ne('open')->fetchAll('id', false);
- if(empty($products)) return false;
- list($teamsGroup, $stakeholderGroup) = $this->getProductMembers($products);
- /* Get white list group. */
- $stmt = $this->dao->select('objectID,account')->from(TABLE_ACL)->where('objectType')->eq('product')->andWhere('objectID')->in($productIDList)->query();
- $whiteListGroup = array();
- while($whiteList = $stmt->fetch()) $whiteListGroup[$whiteList->objectID][$whiteList->account] = $whiteList->account;
- $productAdmins = $this->loadModel('group')->getAdmins($productIDList, 'products'); // Get products' admins.
- /* Get auth users. */
- $authedUsers = $users;
- /* 如果没传users参数,则获取项目关联的所有人。*/
- if(empty($users)) $authedUsers += $this->getObjectsAuthedUsers($products, 'product', $stakeholderGroup, $teamsGroup, $whiteListGroup, $productAdmins, array(), array());
- /* Get all products user view. */
- $userViews = $this->dao->select("account,products")->from(TABLE_USERVIEW)->where('account')->in($authedUsers)->fetchPairs('account', 'products');
- /* Judge auth and update view. */
- foreach(array_filter($authedUsers) as $account)
- {
- $view = isset($userViews[$account]) ? $userViews[$account] : '';
- $latestView = $view;
- foreach($products as $productID => $product)
- {
- $latestView = $this->getLatestUserView($account, $latestView, $product, 'product', $stakeholderGroup, $teamsGroup, $whiteListGroup, $productAdmins, array(), array());
- }
- if($view != $latestView)
- {
- if(!isset($userViews[$account]))
- {
- $userView = new stdclass();
- $userView->account = $account;
- $userView->products = $latestView;
- $userView->projects = $userView->programs = $userView->sprints = '';
- $this->dao->insert(TABLE_USERVIEW)->data($userView)->exec();
- }
- else
- {
- $this->dao->update(TABLE_USERVIEW)->set('products')->eq($latestView)->where('account')->eq($account)->exec();
- }
- }
- }
- return true;
- }
- /**
- * 更新迭代下的用户访问视图。
- * Update sprint view.
- *
- * @param array $sprintIDList
- * @param array $users
- * @access private
- * @return bool
- */
- public function updateSprintView($sprintIDList, $users)
- {
- $sprints = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->in($sprintIDList)->andWhere('acl')->ne('open')->fetchAll('id');
- if(empty($sprints)) return false;
- $projectIDList = array();
- foreach($sprints as $sprint) $projectIDList[$sprint->project] = $sprint->project;
- $stmt = $this->dao->select('root,account')->from(TABLE_TEAM)->where('type')->in('project,execution')->andWhere('root')->in(array_merge($sprintIDList, $projectIDList))->andWhere('root')->ne(0)->query();
- $teamsGroup = array();
- while($team = $stmt->fetch()) $teamsGroup[$team->root][$team->account] = $team->account;
- $stmt = $this->dao->select('objectID,account')->from(TABLE_ACL)->where('objectType')->eq('sprint')->andWhere('objectID')->in($sprintIDList)->query();
- $whiteListGroup = array();
- while($whiteList = $stmt->fetch()) $whiteListGroup[$whiteList->objectID][$whiteList->account] = $whiteList->account;
- $stakeholderGroup = $this->loadModel('stakeholder')->getStakeholderGroup($projectIDList); // Get parent project stakeholders.
- $executionAdmins = $this->loadModel('group')->getAdmins($sprintIDList, 'executions'); // Get executions' admins.
- $authedUsers = $users;
- if(empty($users)) $authedUsers += $this->getObjectsAuthedUsers($sprints, 'sprint', $stakeholderGroup, $teamsGroup, $whiteListGroup, $executionAdmins, array(), array());
- $userViews = $this->dao->select("account,sprints")->from(TABLE_USERVIEW)->where('account')->in($authedUsers)->fetchPairs('account', 'sprints'); // Get all sprints user view.
- foreach(array_filter($authedUsers) as $account)
- {
- $view = isset($userViews[$account]) ? $userViews[$account] : '';
- $latestView = $view;
- foreach($sprints as $sprint)
- {
- $latestView = $this->getLatestUserView($account, $latestView, $sprint, 'sprint', $stakeholderGroup, $teamsGroup, $whiteListGroup, $executionAdmins, array(), array());
- }
- if($view != $latestView)
- {
- if(!isset($userViews[$account]))
- {
- $userView = new stdclass();
- $userView->account = $account;
- $userView->sprints = $latestView;
- $userView->projects = $userView->programs = $userView->products = '';
- $this->dao->insert(TABLE_USERVIEW)->data($userView)->exec();
- }
- else
- {
- $this->dao->update(TABLE_USERVIEW)->set('sprints')->eq($latestView)->where('account')->eq($account)->exec();
- }
- }
- }
- return true;
- }
- /**
- * 获取该对象的关联用户。
- * Get objects authed users.
- *
- * @param array $objects
- * @param string $objectType
- * @param array $stakeholderGroup
- * @param array $teamsGroup
- * @param array $whiteListGroup
- * @param array $adminsGroup
- * @param array $parentStakeholderGroup
- * @param array $parentPMGroup
- * @access private
- * @return array
- */
- private function getObjectsAuthedUsers($objects, $objectType, $stakeholderGroup, $teamsGroup, $whiteListGroup, $adminsGroup, $parentStakeholderGroup, $parentPMGroup)
- {
- $authedUsers = array();
- foreach($objects as $object)
- {
- $stakeholders = zget($stakeholderGroup, $object->id, array());
- $teams = zget($teamsGroup, $object->id, array());
- $whiteList = zget($whiteListGroup, $object->id, array());
- $admins = zget($adminsGroup, $object->id, array());
- if($objectType == 'sprint') $parentTeams = zget($teamsGroup, $object->project, array());
- if($objectType == 'program' && $object->acl == 'program')
- {
- $parents = explode(',', $object->path);
- foreach($parents as $parentID)
- {
- $stakeholders += zget($parentStakeholderGroup, $parentID, array());
- $stakeholders += zget($parentPMGroup, $parentID, array());
- }
- }
- else if($objectType == 'project' && $object->acl == 'program')
- {
- $stakeholders += zget($parentStakeholderGroup, $object->id, array());
- }
- if($objectType == 'program') $authedUsers += $this->getProgramAuthedUsers($object, $stakeholders, $whiteList, $admins);
- if($objectType == 'project') $authedUsers += $this->getProjectAuthedUsers($object, $stakeholders, $teams, $whiteList, $admins);
- if($objectType == 'product') $authedUsers += $this->getProductViewListUsers($object, $teams, $stakeholders, $whiteList, $admins);
- if($objectType == 'sprint') $authedUsers += $this->getProjectAuthedUsers($object, $stakeholders, array_merge($teams, $parentTeams), $whiteList, $admins);
- /* If you have parent stage view permissions, you have child stage permissions. */
- if($objectType == 'sprint' && $object->type == 'stage' && $object->grade == 2)
- {
- $parentStageAuthedUsers = $this->getParentStageAuthedUsers($object->parent);
- $authedUsers = array_merge($authedUsers, $parentStageAuthedUsers);
- }
- }
- return $authedUsers;
- }
- /**
- * 获取用户对于该对象的最新访问权限。
- * Get latest user view.
- *
- * @param string $account
- * @param string $view
- * @param object $object
- * @param string $objectType
- * @param array $stakeholderGroup
- * @param array $teamsGroup
- * @param array $whiteListGroup
- * @param array $adminsGroup
- * @param array $parentStakeholderGroup
- * @param array $parentPMGroup
- * @access private
- * @return string
- */
- private function getLatestUserView($account, $view, $object, $objectType, $stakeholderGroup, $teamsGroup, $whiteListGroup, $adminsGroup, $parentStakeholderGroup, $parentPMGroup)
- {
- $stakeholders = zget($stakeholderGroup, $object->id, array());
- $teams = zget($teamsGroup, $object->id, array());
- $whiteList = zget($whiteListGroup, $object->id, array());
- $admins = zget($adminsGroup, $object->id, array());
- if(!empty($object->acl) && $object->acl == 'program')
- {
- $stakeholders += zget($parentStakeholderGroup, $object->id, array());
- if($objectType == 'program')
- {
- $stakeholders += zget($parentPMGroup, $object->id, array());
- }
- }
- $hasPriv = false;
- if($objectType == 'program') $hasPriv = $this->checkProgramPriv($object, $account, $stakeholders, $whiteList, $admins);
- if($objectType == 'project') $hasPriv = $this->checkProjectPriv($object, $account, $stakeholders, $teams, $whiteList, $admins);
- if($objectType == 'product') $hasPriv = $this->checkProductPriv($object, $account, $teams, $stakeholders, $whiteList, $admins);
- if($objectType == 'sprint') $hasPriv = $this->checkProjectPriv($object, $account, $stakeholders, $teams, $whiteList, $admins);
- if($hasPriv && strpos(",{$view},", ",{$object->id},") === false) $view .= ",{$object->id}";
- if(!$hasPriv && strpos(",{$view},", ",{$object->id},") !== false) $view = trim(str_replace(",{$object->id},", ',', ",{$view},"), ',');
- return $view;
- }
- /**
- * 检查用户是否有此项目集的查看权限。
- * Check program priv.
- *
- * @param object $program
- * @param string $account
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $admins
- * @access private
- * @return bool
- */
- private function checkProgramPriv($program, $account, $stakeholders = array(), $whiteList = array(), $admins = array())
- {
- /* 当前用户为管理员则判断为有权限。 */
- if(strpos($this->app->company->admins, ',' . $account . ',') !== false) return true;
- /* 当前用户为项目集的PM或创建者则判断为有权限。 */
- if($program->PM == $account || $program->openedBy == $account) return true;
- if($program->acl == 'open') return true; // 如果项目集为公开则判断为有权限。
- if(isset($stakeholders[$account])) return true; // 如果该用户是项目集的干系人则判断为有权限。
- if(isset($whiteList[$account])) return true; // 如果该用户是项目集的白名单成员则判断为有权限。
- if(isset($admins[$account])) return true; // 如果该用户是项目集的管理人员则判断为有权限。
- /* 如果是项目集内公开,则检查所有父项目集的权限。 */
- if($program->parent != 0 && $program->acl == 'program')
- {
- $path = str_replace(",{$program->id},", ',', "{$program->path}");
- $parents = $this->mao->select('openedBy,PM')->from(TABLE_PROGRAM)->where('id')->in($path)->fetchAll();
- foreach($parents as $parent)
- {
- /* 当前用户是其中一个父项目集的PM或创建者则判断为有权限。 */
- if($parent->PM == $account || $parent->openedBy == $account) return true;
- }
- }
- return false;
- }
- /**
- * 检查用户是否有此项目或者迭代的查看权限。
- * Check project priv.
- *
- * @param object $project
- * @param string $account
- * @param array $stakeholders
- * @param array $teams
- * @param array $whiteList
- * @param array $admins
- * @access private
- * @return bool
- */
- private function checkProjectPriv($project, $account, $stakeholders, $teams, $whiteList, $admins = array())
- {
- /* 当前用户为管理员则判断为有权限。 */
- if(strpos($this->app->company->admins, ',' . $account . ',') !== false) return true;
- /* 当前用户为项目集的PO、QD、RD、PM则判断为有权限。 */
- if($project->PO == $account || $project->QD == $account || $project->RD == $account || $project->PM == $account) return true;
- if($project->acl == 'open') return true; // 如果项目为公开则判断为有权限。
- if(isset($stakeholders[$account])) return true; // 如果该用户是项目的干系人则判断为有权限。
- if(isset($teams[$account])) return true; // 如果该用户是项目的团队成员则判断为有权限。
- if(isset($whiteList[$account])) return true; // 如果该用户是项目的白名单成员则判断为有权限。
- if(isset($admins[$account])) return true; // 如果该用户是项目的管理人员则判断为有权限。
- /* 如果是项目类型并且项目集内公开,则检查所有父项目集的权限。 */
- if($project->type == 'project' && $project->parent != 0 && $project->acl == 'program')
- {
- $path = str_replace(",{$project->id},", ',', "{$project->path}");
- $programs = $this->mao->select('openedBy,PM')->from(TABLE_PROJECT)->where('id')->in($path)->fetchAll();
- foreach($programs as $program)
- {
- /* 当前用户是其中一个父项目集的PM或创建者则判断为有权限。 */
- if($program->PM == $account || $program->openedBy == $account) return true;
- }
- }
- /* 如果是迭代并且是私有的,则检查所属项目的权限。 */
- if(($project->type == 'sprint' || $project->type == 'stage' || $project->type == 'kanban') && $project->acl == 'private')
- {
- $project = $this->mao->select('openedBy,PM')->from(TABLE_PROJECT)->where('id')->eq($project->project)->fetch();
- if(empty($project)) return false;
- /* 当前用户是所属项目的PM或创建者则判断为有权限。 */
- if($project->PM == $account || $project->openedBy == $account) return true;
- }
- return false;
- }
- /**
- * 检查用户是否有此产品的查看权限。
- * Check product priv.
- *
- * @param object $product
- * @param string $account
- * @param array $teams
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $admins
- * @access private
- * @return bool
- */
- private function checkProductPriv($product, $account, $teams, $stakeholders, $whiteList, $admins = array())
- {
- if(strpos($this->app->company->admins, ',' . $account . ',') !== false) return true; // 当前用户为管理员则判断为有权限。
- if(strpos(",{$product->reviewer},", ',' . $account . ',') !== false) return true; // 当前用户为产品的审批人则判断为有权限。
- if(strpos(",{$product->PMT},", ',' . $account . ',') !== false) return true; // 当前用户为产品的PMT则判断为有权限。
- /* 当前产品为公开的则判断为有权限。 */
- if($product->acl == 'open') return true;
- /* 当前用户为产品的PO、QD、RD、创建者、反馈负责人、工单负责人则判断为有权限。 */
- if($product->PO == $account || $product->QD == $account || $product->RD == $account || $product->createdBy == $account) return true;
- if(isset($product->feedback) && $product->feedback == $account) return true;
- if(isset($product->ticket) && $product->ticket == $account) return true;
- if(isset($stakeholders[$account])) return true; // 如果该用户是产品的干系人则判断为有权限。
- if(isset($teams[$account])) return true; // 如果该用户是产品的团队成员则判断为有权限。
- if(isset($whiteList[$account])) return true; // 如果该用户是产品的白名单成员则判断为有权限。
- if(isset($admins[$account])) return true; // 如果该用户是产品的管理人员则判断为有权限。
- return false;
- }
- /**
- * Get program authed users.
- *
- * @param object $program
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $admins
- * @access private
- * @return array
- */
- private function getProgramAuthedUsers($program, $stakeholders, $whiteList, $admins)
- {
- $users = array();
- $users[$program->openedBy] = $program->openedBy;
- $users[$program->PM] = $program->PM;
- $users += $stakeholders ? $stakeholders : array();
- $users += $whiteList ? $whiteList : array();
- $users += $admins ? $admins : array();
- $admins = explode(',', trim($this->app->company->admins, ','));
- foreach($admins as $admin) $users[$admin] = $admin;
- /* 如果是项目集内公开,则所有父项目集的PM和创建者都是关系人。 */
- if($program->parent != 0 && $program->acl == 'program')
- {
- $path = str_replace(",{$program->id},", ',', "{$program->path}");
- $parents = $this->mao->select('openedBy,PM')->from(TABLE_PROGRAM)->where('id')->in($path)->fetchAll();
- foreach($parents as $parent)
- {
- $users[$parent->openedBy] = $parent->openedBy;
- $users[$parent->PM] = $parent->PM;
- }
- }
- return $users;
- }
- /**
- * 获取和项目或者迭代相关联的用户。
- * Get project authed users.
- *
- * @param object $project
- * @param array $stakeholders
- * @param array $teams
- * @param array $whiteList
- * @param array $admins
- * @access private
- * @return array
- */
- private function getProjectAuthedUsers($project, $stakeholders, $teams, $whiteList, $admins = array())
- {
- $users = array();
- $users[$project->openedBy] = $project->openedBy;
- $users[$project->PM] = $project->PM;
- $users[$project->PO] = $project->PO;
- $users[$project->QD] = $project->QD;
- $users[$project->RD] = $project->RD;
- $users += $stakeholders ? $stakeholders : array();
- $users += $teams ? $teams : array();
- $users += $whiteList ? $whiteList : array();
- $users += $admins ? $admins : array();
- $admins = explode(',', trim($this->app->company->admins, ','));
- foreach($admins as $admin) $users[$admin] = $admin;
- /* 如果是项目类型并且项目集内公开,则所有父项目集的PM和创建者都是关系人。 */
- if($project->type == 'project' && $project->parent != 0 && $project->acl == 'program')
- {
- $path = str_replace(",{$project->id},", ',', "{$project->path}");
- $programs = $this->mao->select('openedBy,PM')->from(TABLE_PROJECT)->where('id')->in($path)->fetchAll();
- foreach($programs as $program)
- {
- $users[$program->openedBy] = $program->openedBy;
- $users[$program->PM] = $program->PM;
- }
- }
- /* 如果是迭代类型并且是私有的,则所属项目的PM和创建者是关系人。 */
- if(($project->type == 'sprint' || $project->type == 'stage' || $project->type == 'kanban') && $project->acl == 'private')
- {
- $parent = $this->mao->select('openedBy,PM')->from(TABLE_PROJECT)->where('id')->eq($project->project)->fetch();
- if($parent)
- {
- $users[$parent->openedBy] = $parent->openedBy;
- $users[$parent->PM] = $parent->PM;
- }
- }
- return $users;
- }
- /**
- * 获取和产品相关联的用户。
- * Get product view list users.
- *
- * @param object $product
- * @param array $teams
- * @param array $stakeholders
- * @param array $whiteList
- * @param array $admins
- * @access public
- * @return array
- */
- public function getProductViewListUsers($product, $teams = array(), $stakeholders = array(), $whiteList = array(), $admins = array())
- {
- $users = array();
- $users[$product->PO] = $product->PO;
- $users[$product->QD] = $product->QD;
- $users[$product->RD] = $product->RD;
- $users[$product->createdBy] = $product->createdBy;
- if(isset($product->feedback)) $users[$product->feedback] = $product->feedback;
- if(isset($product->ticket)) $users[$product->ticket] = $product->ticket;
- foreach(explode(',', trim($this->app->company->admins, ',')) as $admin) $users[$admin] = $admin;
- foreach(explode(',', trim(zget($product, 'reviewer', ''), ',')) as $account) $users[$account] = $account;
- foreach(explode(',', trim(zget($product, 'PMT', ''), ',')) as $account) $users[$account] = $account;
- if(!$teams || !$stakeholders)
- {
- list($productTeams, $productStakeholders) = $this->getProductMembers(array($product->id => $product));
- if(!$teams) $teams = isset($productTeams[$product->id]) ? $productTeams[$product->id] : array();
- if(!$stakeholders) $stakeholders = isset($productStakeholders[$product->id]) ? $productStakeholders[$product->id] : array();
- }
- if(!$whiteList) $whiteList = $this->dao->select('account')->from(TABLE_ACL)->where('objectType')->eq('product')->andWhere('objectID')->eq($product->id)->fetchPairs();
- if(!$admins) $admins = $this->dao->select('account')->from(TABLE_PROJECTADMIN)->where("FIND_IN_SET({$product->id}, products)")->orWhere('products')->eq('all')->fetchPairs();
- $users += $teams ? $teams : array();
- $users += $stakeholders ? $stakeholders : array();
- $users += $whiteList ? $whiteList : array();
- $users += $admins ? $admins : array();
- return $users;
- }
- /**
- * 获取项目、执行等对象的团队成员。
- * Get team members in object.
- *
- * @param string|array|int $objects
- * @param string $type project|execution
- * @param string $params
- * @param string|array $usersToAppended
- * @access public
- * @return array
- */
- public function getTeamMemberPairs($objects, $type = 'project', $params = '', $usersToAppended = '')
- {
- if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getTeamMembersPairs();
- if(empty($objects) && empty($usersToAppended)) return array();
- $keyField = strpos($params, 'useid') !== false ? 'id' : 'account';
- $users = $this->dao->select("t2.id, t2.account, t2.realname")->from(TABLE_TEAM)->alias('t1')
- ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')
- ->where('t1.type')->eq($type)
- ->andWhere('t1.root')->in($objects)
- ->beginIF($params == 'nodeleted' || empty($this->config->user->showDeleted))->andWhere('t2.deleted')->eq('0')->fi()
- ->fetchAll($keyField);
- if($usersToAppended) $users += $this->dao->select("id, account, realname")->from(TABLE_USER)->where('account')->in($usersToAppended)->fetchAll($keyField);
- if(!$users) return array();
- /* 拼装成用户名为键,真实姓名为值的数组。 */
- foreach($users as $account => $user)
- {
- $firstLetter = ucfirst(substr($user->account, 0, 1)) . ':';
- if(!empty($this->config->isINT)) $firstLetter = '';
- $users[$account] = $firstLetter . ($user->realname ? $user->realname : $user->account);
- }
- /* Put the current user first. */
- return $this->setCurrentUserFirst($users);
- }
- /**
- * 判断一个按钮是否可以点击。
- * Check if a button is clickable.
- *
- * @param object $user
- * @param string $action
- * @static
- * @access public
- * @return bool
- */
- public static function isClickable($user, $action)
- {
- global $config, $app;
- $action = strtolower($action);
- if($action == 'unbind' && empty($user->ranzhi)) return false;
- if($action == 'unlock' && (time() - strtotime($user->locked)) >= $config->user->lockMinutes * 60) return false;
- if($action == 'delete' && strpos($app->company->admins, ",{$user->account},") !== false) return false;
- return true;
- }
- /**
- * 保存一个编辑器模板。
- * Save a editor template.
- *
- * @param object $template
- * @access public
- * @return bool
- */
- public function saveUserTemplate($template)
- {
- $this->dao->insert(TABLE_USERTPL)->data($template)
- ->batchCheck('title, content', 'notempty')
- ->check('title', 'unique', "`type`='{$template->type}' AND account='{$template->account}'")
- ->autoCheck()
- ->exec();
- if(dao::isError()) return false;
- $this->loadModel('score')->create('bug', 'saveTplModal', $this->dao->lastInsertID());
- return !dao::isError();
- }
- /**
- * Save old user template.
- *
- * @param string $type
- * @access public
- * @return void
- */
- public function saveOldUserTemplate($type)
- {
- $template = fixer::input('post')
- ->setDefault('account', $this->app->user->account)
- ->setDefault('type', $type)
- ->stripTags('content', $this->config->allowedTags)
- ->get();
- $condition = "`type`='$type' and account='{$this->app->user->account}'";
- $this->dao->insert(TABLE_USERTPL)->data($template)->batchCheck('title, content', 'notempty')->check('title', 'unique', $condition)->exec();
- if(!dao::isError()) $this->loadModel('score')->create('bug', 'saveTplModal', $this->dao->lastInsertID());
- }
- /**
- * 获取当前用户可以查看的模板列表。
- * Get user templates.
- *
- * @param string $type
- * @access public
- * @return array
- */
- public function getUserTemplates($type)
- {
- return $this->dao->select('id, account, title, content, public')
- ->from(TABLE_USERTPL)
- ->where('type')->eq($type)
- ->andwhere('account', true)->eq($this->app->user->account)
- ->orWhere('public')->eq('1')
- ->markRight(1)
- ->orderBy('id')
- ->fetchAll();
- }
- /**
- * 为 GitLab API 获取用户列表。
- * Get user list for GitLab API.
- *
- * @param array $accountList
- * @access public
- * @return array
- */
- public function getListForGitLabAPI($accountList)
- {
- /* 第二个参数设为空,确保返回的是一个索引数组。*/
- /* Set the second param to empty, to make sure the return is an indexed array. */
- $users = $this->getListByAccounts($accountList, '');
- foreach($users as $user)
- {
- if($user->avatar)
- {
- $user->avatar = common::getSysURL() . $user->avatar;
- continue;
- }
- $user->avatar = "https://www.gravatar.com/avatar/" . md5($user->account) . "?d=identicon&s=80";
- }
- return $users;
- }
- /**
- * 获取可以创建需求的用户。
- * Get users who have authority to create stories.
- *
- * @access public
- * @return array
- */
- public function getCanCreateStoryUsers()
- {
- $users = $this->getPairs('noclosed|nodeleted');
- $groupUsers = $this->dao->select('DISTINCT account')->from(TABLE_USERGROUP)->alias('t1')
- ->leftJoin(TABLE_GROUPPRIV)->alias('t2')->on('t1.group = t2.group')
- ->where('t2.module')->eq('story')
- ->andWhere('t2.method')->in('create,batchCreate')
- ->fetchPairs('account');
- foreach($users as $account => $realname)
- {
- if($realname && (isset($groupUsers[$account]) || strpos($this->app->company->admins, ",{$account},") !== false)) continue;
- unset($users[$account]);
- }
- return $users;
- }
- /**
- * 把第一个超级管理员设置为当前用户。
- * Set the first super admin as current user.
- *
- * @access public
- * @return bool
- */
- public function su()
- {
- $company = $this->dao->select('admins')->from(TABLE_COMPANY)->fetch();
- $admins = explode(',', trim($company->admins, ','));
- if(empty($admins[0])) helper::end('No admin users.');
- $this->app->user = $this->getById($admins[0]);
- return true;
- }
- /**
- * 把当前用户排到最前面。
- * Put the current user first.
- *
- * @param array $users
- * @access public
- * @return array
- */
- public function setCurrentUserFirst($users)
- {
- $account = $this->app->user->account;
- if(!$users || !$account || !isset($users[$account])) return $users;
- return array($account => $users[$account]) + $users;
- }
- }
|