{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Administration: Validate user profiles\n",
    "\n",
    "> * 👟 Ready To Run!\n",
    "* 🔒 Requires Administrator Privileges\n",
    "* 📝 Administration\n",
    "* 👤 User Management\n",
    "\n",
    "Some organizations require member profiles to contain values beyond the minumum required attributes necessary to create a valid user in an ArcGIS Online Organization or ArcGIS Enterprise. For instance, in order to comply with policies and regulations, an organization may require a profile picture or a brief description. This notebook will check attribute values for users of the organization to monitor profiles."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get started, let's import the necessary libraries and connect to our GIS."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import datetime as dt\n",
    "\n",
    "import pandas as pd\n",
    "\n",
    "from arcgis.gis import GIS\n",
    "\n",
    "gis = GIS(\"home\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, let's create a list containing strings that represent all the values that your organization requires (beyond the required attributes for a valid user profile)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "complete_profile = ['description', 'thumbnail', 'access']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll define a function that loops through the list we created and inspects a user object for the values of these attributes. We'll create a list of True/False values for each user regarding the necessary attributes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_missing_profile_attrs(member):\n",
    "    non_compliance = []\n",
    "    for attr in complete_profile:\n",
    "        if getattr(member, attr) == None:\n",
    "            non_compliance.append(False)\n",
    "        else:\n",
    "            non_compliance.append(True)\n",
    "    return non_compliance"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can create a list of users in the GIS and loop through them, calling the function written above to inspect each user object. This will create a dictionary with usernames as the key and the list of True/False values regarding the required attributes as the values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "user_profile_status = {}\n",
    "for user in gis.users.search(\"NOT esri_*\"):\n",
    "    missing_profile_atts = get_missing_profile_attrs(user)\n",
    "    user_profile_status[user.username] = missing_profile_atts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The pandas library can be used to create a dataframe from the above dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>description</th>\n",
       "      <th>thumbnail</th>\n",
       "      <th>access</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>user001</th>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>viewer002</th>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>primary_admin</th>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>publisher001</th>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             description  thumbnail  access\n",
       "user001             False      False    True\n",
       "viewer002             False      False    True\n",
       "primary_admin        False      False    True\n",
       "publisher001           False      False    True"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_profile_df = pd.DataFrame(data=user_profile_status, index=complete_profile).T\n",
    "user_profile_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This dataframe can then be written to a _.csv._ file on your fileshare,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "output_dir = \"/arcgis/home/\"\n",
    "current = str(int(dt.datetime.now().timestamp()))\n",
    "out_file = \"output_org_user_profile\" + \"_\" + current + \".csv\"\n",
    "\n",
    "user_profile_df.to_csv(os.path.join(output_dir, out_file), index_label='username')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and the dataframe can be written to a _.csv_ file item on your Organization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div class=\"item_container\" style=\"height: auto; overflow: hidden; border: 1px solid #cfcfcf; border-radius: 2px; background: #f6fafa; line-height: 1.21429em; padding: 10px;\">\n",
       "                    <div class=\"item_left\" style=\"width: 210px; float: left;\">\n",
       "                    </div>\n",
       "\n",
       "                    <div class=\"item_right\"     style=\"float: none; width: auto; overflow: hidden;\">\n",
       "                        <b>output_org_user_profile_1547747903</b>\n",
       "                        <br/>CSV by primary_admin\n",
       "                        <br/>Last Modified: January 17, 2019\n",
       "                        <br/>0 comments, 0 views\n",
       "                    </div>\n",
       "                </div>\n",
       "                "
      ],
      "text/plain": [
       "<Item title:\"output_org_user_profile_1547747903\" type:CSV owner:primary_admin>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gis.content.add({}, output_dir + out_file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Conclusion\n",
    "\n",
    "This notebook checked attribute values for an organization's users and wrote the results to a _.csv_ file. This file can then be analyzed to validate that all user profiles contain the minimum required attributes as defined by any policies or regulations."
   ]
  }
 ],
 "metadata": {
  "esriNotebookRuntime": {
   "notebookRuntimeName": "ArcGIS Notebook Python 3 Standard",
   "notebookRuntimeVersion": "10.7.1"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
