/** * Creates a log entry with the given data * @param \CMF\Model\User $user User to log against * @param \CMF\Model\Base $item Item to log against * @param string $action The name of the action that has happened * @param string $message An additional verbose message if required * @return void */ public static function add($user = null, $item = null, $action = 'view', $message = '') { $log = array(); // Set the user info if ($user === null) { $user = \CMF\Auth::current_user(); } if ($user !== null) { $log['user_id'] = $user->id; $log['user_type'] = get_class($user); } else { $log['user_id'] = $log['user_type'] = null; } // Set the item data if ($item === null) { $item = \CMF::currentModel(); } if ($item !== null) { $log['item_id'] = $item->id; $log['item_type'] = get_class($item); $log['item_label'] = strip_tags($item->display()); } else { $log['item_id'] = $log['item_type'] = $log['item_label'] = null; } // Action and message $log['action'] = $action; $log['message'] = $message; // Add the log static::$logs_made[] = $log; \DB::insert('logs')->columns(array('date', 'user_id', 'user_type', 'item_id', 'item_type', 'item_label', 'action', 'message'))->values(array(\Date::forge()->format('mysql'), $log['user_id'], $log['user_type'], $log['item_id'], $log['item_type'], $log['item_label'], $log['action'], $log['message']))->execute(); }
public function action_logout() { if (\CMF\Auth::logout()) { \Session::delete('cmf.admin.language'); \Response::redirect('/admin/login', 'location'); } }
public function after($response) { // If a response has been provided, just go with it if (!is_null($response)) { return $response; } // Populate the sidebar $this->sidebar = \Admin::getSidebarConfig(); // Add assets $this->data['assets'] = array('js' => \Arr::get($this->assets, 'js', array()), 'css' => \Arr::get($this->assets, 'css', array())); // JSON encode the JS $this->js['settings'] = $this->getSettings(); $this->data['js_data'] = json_encode($this->js); // Info about the user $user = \CMF\Auth::current_user(); $this->user = array('account' => '/admin/users/' . $user->id . '/edit', 'username' => $user->username, 'super_user' => $user->super_user); // Some vital settings $this->admin_title = \Lang::get('admin.title', array(), \Config::get("cmf.admin.title", '')); $this->base_url = \Admin::$base; $this->modules = \Config::get('cmf.admin.modules', false); $this->current_module = \Admin::$current_module; $this->current_class = \Admin::$current_class; $this->dashboard_title = \Lang::get('admin.modules.' . \Admin::$current_module . '.title', array(), \Config::get('cmf.admin.modules.' . \Admin::$current_module . '.title', \Lang::get('admin.common.dashboard', array(), 'Dashboard'))); $this->headers['X-XSS-Protection'] = 0; return \Response::forge(\View::forge($this->template, $this->data, false), $this->status, $this->headers); }
/** * Create an API key for a user in a particular scope * @return \CMF\Model\User\Apikey */ public function getKey($user, $type, $scope) { $key = new \Model_User_Apikey(); $key->populate(array('user_id' => $user->id, 'user_type' => $type, 'expires_at' => new \DateTime('@' . (strtotime('now') + 25 * 60 * 60)), 'access_token' => \CMF\Auth::forge()->generate_token(), 'scope' => $scope)); \D::manager()->persist($key); \D::manager()->flush(); return $key; }
/** inheritdoc */ public static function displayForm($value, &$settings, $model) { // Set up the values for the select $values = array(); if (isset($value) && $value instanceof \Doctrine\Common\Collections\Collection) { foreach ($value as $val) { $values[] = strval($val->get('id')); } } $target_prop = $settings['mapping']['isOwningSide'] === true ? $settings['mapping']['inversedBy'] : $settings['mapping']['mappedBy']; if (empty($target_prop) || is_null($model->id)) { $target_prop = false; } // Set up the values for the template $settings = static::settings($settings); $target_class = $settings['mapping']['targetEntity']; $target_table = \CMF\Admin::getTableForClass($target_class); $options = $target_class::options(\Arr::get($settings, 'filters', array()), array(), null, null, null, is_array($settings['select2']), \Arr::get($settings, 'group_by')); $settings['required'] = isset($settings['required']) ? $settings['required'] : false; $errors = $model->getErrorsForField($settings['mapping']['fieldName']); $has_errors = count($errors) > 0; $settings['title'] = $settings['title'] . ($settings['required'] ? ' *' : '') . ($has_errors ? ' - ' . $errors[0] : ''); $settings['cid'] = 'field_' . md5($settings['mapping']['fieldName'] . static::type()); $settings['add_link'] = \Uri::create('/admin/' . $target_table . '/create?_mode=inline&_cid=' . $settings['cid'] . ($target_prop !== false ? '&' . $target_prop . '=' . $model->id : '')); $settings['singular'] = $target_class::singular(); $settings['icon'] = $target_class::icon(); $settings['is_select2'] = false; // Permissions $settings['can_edit'] = \CMF\Auth::can('edit', $target_class); $settings['can_create'] = \CMF\Auth::can('create', $target_class) && $settings['can_edit']; $settings['create'] = $settings['create'] && $settings['can_create']; $settings['edit'] = $settings['edit'] && $settings['can_edit']; if ($settings['transfer'] === true) { $settings['input_attributes']['class'] .= ' input-xxlarge'; $transfer_options = array(); foreach ($options as $key => $value) { $transfer_options[] = array('value' => $key, 'content' => $value); } $content = strval(\View::forge('admin/fields/collection/multiselect.twig', array('settings' => $settings, 'options' => $options, 'values' => $values), false)); return array('content' => $content, 'widget' => $settings['widget'], 'assets' => array('js' => array('/admin/assets/js/bootstrap-transfer.js', '/admin/assets/js/fields/collection/transfer.js'), 'css' => array('/admin/assets/css/bootstrap-transfer.css')), 'js_data' => array('options' => $transfer_options, 'values' => $values, 'edit' => $settings['edit'], 'create' => $settings['create'])); } else { if (is_array($settings['select2'])) { $settings['sortable'] = $settings['select2']['sortable'] = $target_class::sortable() && isset($settings['mapping']['orderBy']) && isset($settings['mapping']['orderBy']['pos']) && $settings['mapping']['orderBy']['pos'] == 'ASC'; $settings['is_select2'] = true; $settings['input_attributes']['class'] .= 'input-xxlarge select2'; $content = strval(\View::forge('admin/fields/collection/multiselect.twig', array('settings' => $settings, 'options' => $options, 'values' => $values), false)); $settings['select2']['placeholder'] = 'click to select a ' . strtolower($settings['singular']) . '...'; $settings['select2']['target_table'] = $target_table; // Permissions $settings['select2']['create'] = $settings['create']; $settings['select2']['edit'] = $settings['edit']; return array('content' => $content, 'widget' => $settings['widget'], 'assets' => array('css' => array('/admin/assets/select2/select2.css'), 'js' => array('/admin/assets/select2/select2.min.js', '/admin/assets/js/fields/select2.js')), 'js_data' => $settings['select2']); } } $settings['input_attributes']['class'] .= ' input-xxlarge'; return array('content' => strval(\View::forge('admin/fields/collection/multiselect.twig', array('settings' => $settings, 'options' => $options, 'values' => $values), false)), 'assets' => array('js' => array('/admin/assets/js/fields/collection/multiselect.js')), 'widget' => false); return; }
/** inheritdoc */ public static function displayForm($value, &$settings, $model) { $id = isset($value) ? $value->id : ''; $settings = static::settings($settings); $settings['cid'] = 'field_' . md5($settings['mapping']['fieldName'] . static::type()); $required = isset($settings['required']) ? $settings['required'] : false; $include_label = isset($settings['label']) ? $settings['label'] : true; $target_class = $settings['mapping']['targetEntity']; $target_table = \CMF\Admin::getTableForClass($target_class); $target_prop = $settings['mapping']['isOwningSide'] === true ? $settings['mapping']['inversedBy'] : $settings['mapping']['mappedBy']; if (empty($target_prop) || is_null($model->id)) { $target_prop = false; } $add_link = \Uri::create('/admin/' . $target_table . '/create?_mode=inline&_cid=' . $settings['cid'] . ($target_prop !== false ? '&' . $target_prop . '=' . $model->id : '')); $options = $target_class::options(\Arr::get($settings, 'filters', array()), array(), null, null, null, is_array($settings['select2']), \Arr::get($settings, 'group_by')); $has_controls = $settings['create'] !== false; // Description? $description = isset($settings['description']) ? '<span class="help-block">' . $settings['description'] . '</span>' : ''; if ($settings['allow_empty']) { $options = array('' => '') + $options; } $errors = $model->getErrorsForField($settings['mapping']['fieldName']); $has_errors = count($errors) > 0; $input_attributes = $settings['input_attributes']; $label = !$include_label ? '' : \Form::label($settings['title'] . ($required ? ' *' : '') . ($has_errors ? ' - ' . $errors[0] : ''), $settings['mapping']['fieldName'], array('class' => 'item-label')); $add_link = html_tag('a', array('href' => $add_link, 'class' => 'btn btn-mini btn-create'), '<i class="fa fa-plus"></i> create ' . strtolower($target_class::singular())); // Permissions $settings['can_edit'] = \CMF\Auth::can('edit', $target_class); $settings['can_create'] = \CMF\Auth::can('create', $target_class) && $settings['can_edit']; $settings['create'] = $settings['create'] && $settings['can_create']; $settings['edit'] = $settings['edit'] && $settings['can_edit']; if ($settings['create'] === false) { $add_link = " "; } $controls_top = html_tag('div', array('class' => 'controls-top'), $add_link); if (is_array($settings['select2'])) { $input_attributes['class'] .= 'input-xxlarge select2'; $input = \Form::select($settings['mapping']['fieldName'], $id, $options, $input_attributes); $settings['select2']['placeholder'] = 'click to select ' . strtolower($target_class::singular()) . '...'; $settings['select2']['target_table'] = $target_table; // Permissions $settings['select2']['create'] = $settings['create']; $settings['select2']['edit'] = $settings['edit']; if (!$required) { $settings['select2']['allowClear'] = true; } return array('content' => html_tag('div', array('class' => 'controls control-group' . ($has_controls ? ' field-with-controls' : '') . ($has_errors ? ' error' : ''), 'id' => $settings['cid']), $label . $description . $input . $controls_top) . '<div class="clear"><!-- --></div>', 'widget' => false, 'assets' => array('css' => array('/admin/assets/select2/select2.css'), 'js' => array('/admin/assets/select2/select2.min.js', '/admin/assets/js/fields/select2.js')), 'js_data' => $settings['select2']); } $input_attributes['class'] .= ' input-xxlarge'; $input = \Form::select($settings['mapping']['fieldName'], $id, $options, $input_attributes); if (isset($settings['wrap']) && $settings['wrap'] === false) { return $label . $input; } return html_tag('div', array('class' => 'controls control-group' . ($has_controls ? ' field-with-controls' : '') . ($has_errors ? ' error' : ''), 'id' => $settings['cid']), $label . $description . $input . $controls_top) . '<div class="clear"><!-- --></div>'; }
public function authorise() { // If there's a valid session already, allow access $user_type = \Input::param('user_type') ?: 'Admin\\Model_User'; if (\CMF\Auth::logged_in(null, $user_type)) { return; } $auth = explode(' ', \Input::headers('Authorization', ' ')); $sent_key = \Arr::get($auth, 1); // Try and find a valid key $key = \CMF\Model\User\Apikey::select('item')->where('item.access_token = :key')->andWhere('item.expires_at > :now')->setParameter('key', $sent_key)->setParameter('now', new \DateTime())->getQuery()->getResult(); // Check the scope of the key, if one was found if (count($key)) { $key = $key[0]; if ($key->scope == 'api') { return; } } throw new \HttpException('Login Required', \HttpException::UNAUTHORIZED); }
/** inheritdoc */ public static function displayForm($value, &$settings, $model) { if (!\CMF\Auth::can(array('view', 'edit'), 'CMF\\Model\\Permission')) { return ''; } // Kick the permissions and get the active classes \CMF\Auth::create_permissions(); $all_actions = \CMF\Auth::all_actions(); $activeClasses = \CMF\Admin::activeClasses(); // Set up the values $values = array(); if (isset($value) && ($value instanceof \Doctrine\Common\Collections\Collection || is_array($value))) { foreach ($value as $val) { $resource = $val->resource; $action = $val->action; $actions = isset($values[$resource]) ? $values[$resource] : array(); if (!in_array($action, $actions)) { $actions[] = $action; } $values[$resource] = $actions; } } // Get the resources defined in the config $extra_resources = \CMF\Auth::extra_resources(); $resources = array(); $resource_group = array('title' => \Lang::get('admin.common.resources'), 'classes' => array()); $classes_index = 0; // Set the values of the resources foreach ($extra_resources as $resource_id => $extra_resource) { $extra_resource['values'] = isset($values[$resource_id]) ? $values[$resource_id] : array(); $resource_group['classes'][$resource_id] = $extra_resource; } // If there are resources, add them at the top and update the classes index if (count($resource_group['classes']) > 0) { $resources[] = $resource_group; $classes_index = 1; } $resources[] = array('title' => \Lang::get('admin.common.content_types'), 'classes' => array()); // Build the resources list... foreach ($activeClasses as $class_name => $classes) { if (count($classes) > 1) { $class_group = array(); foreach ($classes as $group_class) { $resource_title = $group_class::_static() ? $group_class::singular() : $group_class::plural(); $resource_icon = $group_class::icon(); $class_group[$group_class] = array('title' => $resource_title, 'icon' => $resource_icon, 'actions' => $group_class::_static() ? array('view', 'edit') : $all_actions, 'values' => isset($values[$group_class]) ? $values[$group_class] : array()); } uasort($class_group, function ($a, $b) { return strcmp(strtolower($a['title']), strtolower($b['title'])); }); $resources[] = array('title' => $class_name::plural(), 'classes' => $class_group); } else { $resource_title = $class_name::_static() ? $class_name::singular() : $class_name::plural(); $resource_icon = $class_name::icon(); $resources[$classes_index]['classes'][$class_name] = array('title' => $resource_title, 'icon' => $resource_icon, 'actions' => $class_name::_static() ? array('view', 'edit') : $all_actions, 'values' => isset($values[$class_name]) ? $values[$class_name] : array()); } } uasort($resources[$classes_index]['classes'], function ($a, $b) { return strcmp(strtolower($a['title']), strtolower($b['title'])); }); $content = strval(\View::forge('admin/fields/auth/permissions.twig', array('settings' => $settings, 'resources' => $resources, 'actions' => $all_actions), false)); return array('content' => $content, 'widget' => true, 'widget_title' => $settings['title'], 'assets' => array()); }
/** * Processes the config and generates data for the template to render the sidebar * @return array The sidebar config */ public static function getSidebarConfig() { $sidebar_config = \Config::get(static::$sidebar_config_path, array()); $current_group = 0; $output = array(array('heading' => false, 'items' => array())); $class_prefix = static::$current_module != '_root_' ? ucfirst(static::$current_module) . '\\' : ''; // Check if the first item is a heading if (isset($sidebar_config[0]['heading'])) { $item = array_shift($sidebar_config); $output[0]['heading'] = $item['heading']; } foreach ($sidebar_config as $item) { if (isset($item['heading'])) { $current_group++; $output[$current_group] = array('heading' => $item['heading'], 'items' => array()); } else { if (isset($item['model'])) { $class_name = $class_prefix . $item['model']; if (!class_exists($class_name)) { $class_name = $item['model']; } if (!\CMF\Auth::can('view', $class_name)) { continue; } $metadata = $class_name::metadata(); $output[$current_group]['items'][] = array('icon' => isset($item['icon']) ? $item['icon'] : $class_name::icon(), 'title' => isset($item['title']) ? $item['title'] : $class_name::plural(), 'href' => '/admin/' . $metadata->table['name'], 'class' => $class_name, 'active' => $class_name === static::$current_class); } else { if (isset($item['link'])) { if (!isset($item['title'])) { $parts = explode('/', $item['link']); $item['title'] = \Inflector::humanize(str_replace('-', ' ', array_pop($parts))); } $uri = trim(\Input::uri(), '/'); $cmp = trim($item['link'], '/'); $output[$current_group]['items'][] = array('icon' => isset($item['icon']) ? $item['icon'] : 'dashboard', 'title' => $item['title'], 'href' => $item['link'], 'active' => strpos($uri, $cmp) === 0); } } } } return $output; }
/** * Validates a user password & ensures an encrypted password is set * * @see \CMF\Model\User::_event_before_save() */ private function _ensure_and_validate_password() { if (!empty($this->password)) { $this->encrypted_password = Auth::encrypt_password($this->password); } if (empty($this->encrypted_password)) { throw new \Exception(\Lang::get('admin.validation.required', array('field' => 'Password'))); } }
/** * For asyncronous saving - populates a model with the posted data and responds in JSON */ public function action_populate($table_name, $id = null) { // Find class name and metadata etc $class_name = \Admin::getClassForTable($table_name); if ($class_name === false) { return $this->show404(null, "type"); } if (!\CMF\Auth::can('edit', $class_name)) { return $this->show403('action_singular', array('action' => \Lang::get('admin.verbs.edit'), 'resource' => strtolower($class_name::singular()))); } // Set the output content type $this->headers = array("Content-Type: text/plain"); // If $id is null, we're populating multiple items if ($id === null) { // Construct the output $result = array('success' => true, 'num_updated' => 0); $post_data = \Input::post(); $ids = array_keys($post_data); $em = \D::manager(); if (count($ids) == 0) { return \Response::forge(json_encode($result), $this->status, $this->headers); } // Get the items we need to save $items = $class_name::select('item')->where('item.id IN(?1)')->setParameter(1, $ids)->getQuery()->getResult(); if (count($items) == 0) { return \Response::forge(json_encode($result), $this->status, $this->headers); } foreach ($items as $item) { $id = $item->id; if (!isset($post_data[$id])) { continue; } $result['num_updated'] += 1; $data = $post_data[$id]; $item->populate($data, false); if (!$item->validate()) { $result['success'] = false; } $em->persist($item); } // Try and save them all try { $em->flush(); } catch (\Exception $e) { $result['success'] = false; $result['error'] = $e->getMessage(); } // Return the JSON response return \Response::forge(json_encode($result), $this->status, $this->headers); } // Find the model, return 404 if not found $model = $class_name::find($id); if (is_null($model)) { return $this->show404(null, "item"); } // Populate with the POST data $model->populate(\Input::post(), false); // Construct the output $result = array('success' => false); // Check validation if ($model->validate()) { $result['success'] = true; } else { $result['validation_errors'] = $model->errors; } // Try and save it try { $em = \D::manager(); $em->persist($model); $em->flush(); $result['updated_at'] = $model->updated_at->format("d/m/Y \\a\\t H:i:s"); } catch (\Exception $e) { $result['success'] = false; $result['error'] = $e->getMessage(); } // Return the JSON response return \Response::forge(json_encode($result), $this->status, $this->headers); }
/** * Gets called from action_index() when a model is found to extend CMF\Model|Node * @param string $class_name * @return void */ public function treeView($class_name) { \Admin::setCurrentClass($class_name); $metadata = $class_name::metadata(); // Create static items \Admin::createStaticInstances($metadata); // Add some context for the template $this->plural = $class_name::plural(); $this->singular = $class_name::singular(); $this->icon = $class_name::icon(); // Get permissions $can_create = \CMF\Auth::can('create', $class_name); $can_edit = \CMF\Auth::can('edit', $class_name); $can_delete = \CMF\Auth::can('delete', $class_name); $can_manage = \CMF\Auth::can(array('view', 'edit'), 'CMF\\Model\\Permission'); $classes = array(); $classes[$class_name] = array('plural' => $this->plural, 'singular' => $this->singular, 'icon' => $this->icon, 'table_name' => $metadata->table['name'], 'can_create' => $can_create && $can_edit, 'can_edit' => $can_edit, 'can_delete' => $can_delete, 'superclass' => $class_name::superclass(), 'allowed_children' => $class_name::allowedChildren(), 'allowed_parents' => $class_name::allowedParents()); foreach ($metadata->subClasses as $sub_class) { $subclass_metadata = $sub_class::metadata(); $classes[$sub_class] = array('static' => $sub_class::_static(), 'superlock' => $sub_class::superlock(), 'plural' => $sub_class::plural(), 'singular' => $sub_class::singular(), 'icon' => $sub_class::icon(), 'table_name' => $subclass_metadata->table['name'], 'can_create' => \CMF\Auth::can('create', $sub_class), 'can_edit' => \CMF\Auth::can('edit', $sub_class), 'can_delete' => \CMF\Auth::can('delete', $sub_class), 'superclass' => false, 'allowed_children' => $sub_class::allowedChildren(), 'allowed_parents' => $sub_class::allowedParents(), 'disallowed_children' => $sub_class::disallowedChildren(), 'disallowed_parents' => $sub_class::disallowedParents()); } // Item-specific permissions $user = \CMF\Auth::current_user(); $item_permissions = array(); $ids = array(); $excluded_ids = array(); $root_node = $class_name::getRootNode(true); $repo = \D::manager()->getRepository($class_name); $qb = $repo->getNodesHierarchyQueryBuilder($root_node); $this->tree_errors = null; $this->tree_is_valid = true; // If we have URLs, join them to the query if ($class_name::hasUrlField()) { $qb->addSelect('url, alias')->leftJoin('node.url', 'url')->leftJoin('url.alias', 'alias'); } $q = $qb->getQuery(); // Set the query hint if multi lingual! if (\CMF\Doctrine\Extensions\Translatable::enabled()) { $q->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'); } //$tree = $this->processTreeNodes(\D::manager()->getRepository($class_name)->childrenHierarchy($root_node), $metadata, $ids); $tree = $this->processTreeNodes($repo->buildTree($q->getArrayResult()), $metadata, $ids); if (!$user->super_user) { $permissions = \CMF\Model\Permission::select('item.id, item.action, item.resource, item.item_id')->leftJoin('item.roles', 'roles')->where("item.resource = '{$class_name}'")->andWhere("item.item_id IN(?1)")->andWhere("roles IN (?2)")->setParameter(1, $ids)->setParameter(2, $user->roles->toArray())->getQuery()->getArrayResult(); foreach ($permissions as $permission) { $item_actions = isset($item_permissions[$permission['item_id']]) ? $item_permissions[$permission['item_id']] : array(); $item_actions[] = $permission['action']; $item_permissions[$permission['item_id']] = $item_actions; } foreach ($item_permissions as $item_id => $item_actions) { if (in_array('none', $item_actions) || count($item_actions) > 0 && !in_array('view', $item_actions)) { $excluded_ids[] = $item_id; } } $tree = $this->filterTreeNodes($tree, $excluded_ids); } else { $this->tree_errors = $repo->verify(); $this->tree_is_valid = $this->tree_errors === true; } // Import actions $importMethods = $class_name::importMethods(); // Add more context for the template $this->table_name = $metadata->table['name']; $this->template = 'admin/item/tree.twig'; $this->superlock = $class_name::superlock(); $this->num_nodes = count($tree); // Permissions $this->can_create = $can_create && $can_edit; $this->can_edit = $can_edit; $this->can_delete = $can_delete; $this->can_manage = $can_manage; $this->can_import = !empty($importMethods) && $can_manage; // Add the stuff for JS $this->js['tree'] = $tree; $this->js['item_permissions'] = $item_permissions; $this->js['excluded_ids'] = $excluded_ids; $this->js['classes'] = $classes; $this->js['table_name'] = $metadata->table['name']; $this->js['plural'] = $this->plural; $this->js['singular'] = $this->singular; $this->js['class_name'] = $class_name; // Permissions for JS $this->js['can_create'] = $can_create && $can_edit; $this->js['can_edit'] = $can_edit; $this->js['can_delete'] = $can_delete; $this->js['can_manage'] = $can_manage; }