From 646b5518bbd33c6979cac548adca2416d401833a Mon Sep 17 00:00:00 2001
From: Tom Galloway
Date: Wed, 16 Jan 2013 13:08:48 +0000
Subject: [PATCH 1/3] withsqlite is now retrieved from github. Manage User &
Groups pages now display correctly but don't do anything yet.
---
.gitignore | 1 +
Makefile | 9 ++++++++-
modules/installed/system/users.py | 19 ++++++++++---------
start.sh | 1 -
4 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3b943e1bb..d5be6856d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,4 @@ cherrypy.config
data/users.sqlite3
predepend
build/
+*.pid
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 72d916965..f5bf865b9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
#SHELL := /bin/bash
MAKE=make
BUILD_DIR = build
+VENDOR_DIR = vendor
#TODO: add install target
@@ -10,12 +11,15 @@ COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS))
PWD=`pwd`
## Catch-all tagets
-default: predepend cfg cherrypy.config dirs template css docs dbs $(BUILD_DIR)/exmachina #$(BUILD_DIR)/bjsonrpc
+default: predepend cfg cherrypy.config dirs template css docs dbs $(BUILD_DIR)/exmachina $(VENDOR_DIR)/withsqlite #$(BUILD_DIR)/bjsonrpc
all: default
build:
mkdir -p $(BUILD_DIR)
+vendor:
+ mkdir -p $(VENDOR_DIR)
+
predepend:
sudo sh -c "apt-get install augeas-tools python-bjsonrpc python-augeas python-simplejson pandoc python-cheetah"
touch predepend
@@ -23,6 +27,9 @@ predepend:
$(BUILD_DIR)/exmachina: build
git clone git://github.com/tomgalloway/exmachina $(BUILD_DIR)/exmachina
+$(VENDOR_DIR)/withsqlite: vendor
+ git clone git://github.com/jvasile/withsqlite.git $(VENDOR_DIR)/withsqlite
+
$(BUILD_DIR)/bjsonrpc: build
git clone git://github.com/deavid/bjsonrpc.git $(BUILD_DIR)/bjsonrpc
diff --git a/modules/installed/system/users.py b/modules/installed/system/users.py
index c4ac97771..81e747b2f 100644
--- a/modules/installed/system/users.py
+++ b/modules/installed/system/users.py
@@ -5,22 +5,23 @@ from plugin_mount import PagePlugin, FormPlugin
import cfg
from forms import Form
from util import *
+from pprint import pprint
class users(PagePlugin):
order = 20 # order of running init in PagePlugins
def __init__(self, *args, **kwargs):
PagePlugin.__init__(self, *args, **kwargs)
self.register_page("sys.users")
+ self.register_page("sys.users.add")
+ self.register_page("sys.users.edit")
@cherrypy.expose
@require()
def index(self):
- parts = self.forms('/sys/config')
- parts['title']=_("Manage Users and Groups")
- return self.fill_template(**parts)
+ return self.fill_template(title="Manage Users and Groups", sidebar_right="""Add User
Edit Users""")
class add(FormPlugin, PagePlugin):
- url = ["/sys/users"]
+ url = ["/sys/users/add"]
order = 30
sidebar_left = ''
@@ -63,10 +64,10 @@ class add(FormPlugin, PagePlugin):
msg = add_message(msg, "%s saved." % username)
main = self.make_form(username, name, email, message=msg)
- return self.fill_template(title="", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right)
+ return self.fill_template(title="Manage Users and Groups", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right)
class edit(FormPlugin, PagePlugin):
- url = ["/sys/users"]
+ url = ["/sys/users/edit"]
order = 35
sidebar_left = ''
@@ -77,7 +78,7 @@ class edit(FormPlugin, PagePlugin):
system.
Deleting users is permanent!
""" % (cfg.product_name, cfg.box_name))
def main(self, msg=''):
- users = cfg.users.keys()
+ users = cfg.users
add_form = Form(title=_("Edit or Delete User"), action="/sys/users/edit", message=msg)
add_form.html('Delete
')
for uname in sorted(users.keys()):
@@ -114,7 +115,7 @@ class edit(FormPlugin, PagePlugin):
else:
msg.add = _("Must specify at least one valid, existing user.")
main = self.make_form(msg=msg.text)
- return self.fill_template(title="", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right)
+ return self.fill_template(title="Manage Users and Groups", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right)
sidebar_right = ''
u = cfg.users[kwargs['username']]
@@ -125,4 +126,4 @@ class edit(FormPlugin, PagePlugin):
main = _("""Edit User '%s'""" % u['username'])
sidebar_right = ''
- return self.fill_template(title="", main=main, sidebar_left=self.sidebar_left, sidebar_right=sidebar_right)
+ return self.fill_template(title="Manage Users and Groups", main=main, sidebar_left=self.sidebar_left, sidebar_right=sidebar_right)
diff --git a/start.sh b/start.sh
index 1a16d1a5f..4be20c1b6 100755
--- a/start.sh
+++ b/start.sh
@@ -1,7 +1,6 @@
#! /bin/sh
PYTHONPATH=build/exmachina:$PYTHONPATH
-PYTHONPATH=build/bjsonrpc:$PYTHONPATH
export PYTHONPATH
From a312b6d288dc2f978237c1d5e309972d3c873327 Mon Sep 17 00:00:00 2001
From: Tom Galloway
Date: Wed, 16 Jan 2013 15:05:04 +0000
Subject: [PATCH 2/3] Removed changes to get withsqlite from github as it's a
different version?
---
Makefile | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
index f5bf865b9..72d916965 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,6 @@
#SHELL := /bin/bash
MAKE=make
BUILD_DIR = build
-VENDOR_DIR = vendor
#TODO: add install target
@@ -11,15 +10,12 @@ COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS))
PWD=`pwd`
## Catch-all tagets
-default: predepend cfg cherrypy.config dirs template css docs dbs $(BUILD_DIR)/exmachina $(VENDOR_DIR)/withsqlite #$(BUILD_DIR)/bjsonrpc
+default: predepend cfg cherrypy.config dirs template css docs dbs $(BUILD_DIR)/exmachina #$(BUILD_DIR)/bjsonrpc
all: default
build:
mkdir -p $(BUILD_DIR)
-vendor:
- mkdir -p $(VENDOR_DIR)
-
predepend:
sudo sh -c "apt-get install augeas-tools python-bjsonrpc python-augeas python-simplejson pandoc python-cheetah"
touch predepend
@@ -27,9 +23,6 @@ predepend:
$(BUILD_DIR)/exmachina: build
git clone git://github.com/tomgalloway/exmachina $(BUILD_DIR)/exmachina
-$(VENDOR_DIR)/withsqlite: vendor
- git clone git://github.com/jvasile/withsqlite.git $(VENDOR_DIR)/withsqlite
-
$(BUILD_DIR)/bjsonrpc: build
git clone git://github.com/deavid/bjsonrpc.git $(BUILD_DIR)/bjsonrpc
From c4cddbfc0e42afb8e69dce08b561ac00b0f07b35 Mon Sep 17 00:00:00 2001
From: Tom Galloway
Date: Mon, 21 Jan 2013 10:30:52 +0000
Subject: [PATCH 3/3] Changes to get user management screens started. Updated
UserStore to add all expected functions. Added tests for these functions.
---
model.py | 9 +--
modules/installed/lib/user_store.py | 38 +++++++++++-
modules/installed/system/users.py | 24 ++++----
test.sh | 9 +++
tests/test_user_store.py | 86 ++++++++++++++++++++++++++++
tests/testdata/users.sqlite3 | Bin 0 -> 3072 bytes
6 files changed, 148 insertions(+), 18 deletions(-)
create mode 100755 test.sh
create mode 100644 tests/test_user_store.py
create mode 100644 tests/testdata/users.sqlite3
diff --git a/model.py b/model.py
index d3807d0b1..e0b3cd20d 100644
--- a/model.py
+++ b/model.py
@@ -1,14 +1,15 @@
class User(dict):
- """ Every user must have keys for a username, name, password (this
+ """ Every user must have keys for a username, name, passphrase (this
is a md5 hash of the password), groups, and an email address. They can be
blank or None, but the keys must exist. """
def __init__(self, dict=None):
- for key in ['username', 'name', 'password', 'email']:
+ for key in ['username', 'name', 'passphrase', 'email']:
self[key] = ''
for key in ['groups']:
self[key] = []
- for key in dict:
- self[key] = dict[key]
+ if dict:
+ for key in dict:
+ self[key] = dict[key]
def __getattr__(self, attr):
return None
diff --git a/modules/installed/lib/user_store.py b/modules/installed/lib/user_store.py
index a4042c102..236b73a8f 100644
--- a/modules/installed/lib/user_store.py
+++ b/modules/installed/lib/user_store.py
@@ -12,10 +12,42 @@ class UserStore(UserStoreModule, sqlite_db):
self.db_file = cfg.user_db
sqlite_db.__init__(self, self.db_file, autocommit=True)
self.__enter__()
+
def close(self):
- self.__exit__()
- def expert(self):
- return False
+ self.__exit__(None,None,None)
+
+ def expert(self, username=None):
+ groups = self.attr(username,"groups")
+ if not groups:
+ return False
+ return 'expert' in groups
+
+ def attr(self, username=None, field=None):
+ return self.get(username)[field]
+
+ def get(self,username=None):
+ return User(sqlite_db.get(self,username))
+
+ def exists(self, username=None):
+ try:
+ user = self.get(username)
+ if not user:
+ return False
+ elif user["username"]=='':
+ return False
+ return True
+ except TypeError:
+ return False
+
+ def remove(self,username=None):
+ self.__delitem__(username)
+ self.commit()
+
+ def get_all(self):
+ return self.items()
+
+ def set(self,username=None,user=None):
+ sqlite_db.__setitem__(self,username, user)
class UserStoreOld():
#class UserStore(UserStoreModule):
diff --git a/modules/installed/system/users.py b/modules/installed/system/users.py
index 81e747b2f..63d9c7631 100644
--- a/modules/installed/system/users.py
+++ b/modules/installed/system/users.py
@@ -47,23 +47,25 @@ class add(FormPlugin, PagePlugin):
return form.render()
def process_form(self, username=None, name=None, email=None, md5_password=None, **kwargs):
- msg = ''
+ msg = Message()
- if not username: msg = add_message(msg, _("Must specify a username!"))
- if not md5_password: msg = add_message(msg, _("Must specify a password!"))
+ if not username: msg.add = _("Must specify a username!")
+ if not md5_password: msg.add = _("Must specify a password!")
- if username in cfg.users:
- msg = add_message(msg, _("User already exists!"))
+ if username in cfg.users.keys():
+ msg.add = _("User already exists!")
else:
try:
- cfg.users[username]= User(dict={'username':username, 'name':name, 'email':email, 'password':md5_password})
+ di = {'username':username, 'name':name, 'email':email, 'passphrase':md5_password}
+ new_user = User(dict=di)
+ cfg.users.set(username,new_user)
except:
- msg = add_message(msg, _("Error storing user!"))
+ msg.add = _("Error storing user!")
if not msg:
- msg = add_message(msg, "%s saved." % username)
-
- main = self.make_form(username, name, email, message=msg)
+ msg.add = _("%s saved." % username)
+ cfg.log(msg.text)
+ #main = self.make_form(username, name, email, msg=msg.text)
return self.fill_template(title="Manage Users and Groups", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right)
class edit(FormPlugin, PagePlugin):
@@ -114,7 +116,7 @@ class edit(FormPlugin, PagePlugin):
msg.add(_("User %s does not exist." % username))
else:
msg.add = _("Must specify at least one valid, existing user.")
- main = self.make_form(msg=msg.text)
+ #main = self.make_form(msg=msg.text)
return self.fill_template(title="Manage Users and Groups", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right)
sidebar_right = ''
diff --git a/test.sh b/test.sh
new file mode 100755
index 000000000..4b6f701d4
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+PYTHONPATH=build/exmachina:$PYTHONPATH
+PYTHONPATH=modules/installed/lib:$PYTHONPATH
+PYTHONPATH=vendor:$PYTHONPATH
+
+export PYTHONPATH
+
+python tests/test_user_store.py
diff --git a/tests/test_user_store.py b/tests/test_user_store.py
new file mode 100644
index 000000000..e6a3e8433
--- /dev/null
+++ b/tests/test_user_store.py
@@ -0,0 +1,86 @@
+#! /usr/bin/env python
+# -*- mode: python; mode: auto-fill; fill-column: 80 -*-
+
+import user_store
+from logger import Logger
+import cfg
+import unittest
+import cherrypy
+import plugin_mount
+import os
+from model import User
+cfg.log = Logger()
+
+cherrypy.log.access_file = None
+
+class UserStore(unittest.TestCase):
+ """Test each function of user_store to confirm they work as expected"""
+
+ def setUp(self):
+ cfg.user_db = os.path.join(cfg.file_root, "tests/testdata/users");
+ self.userstore = plugin_mount.UserStoreModule.get_plugins()[0]
+
+ def tearDown(self):
+ for user in self.userstore.get_all():
+ self.userstore.remove(user[0])
+ self.userstore.close()
+
+ def test_user_does_not_exist(self):
+ self.assertEqual(self.userstore.exists("notausername"),False)
+
+ def test_user_does_exist(self):
+ self.add_user("isausername", False)
+ self.assertEqual(self.userstore.exists("isausername"),True)
+
+ def test_add_user(self):
+ self.assertEqual(len(self.userstore.items()),0)
+ self.add_user("test_user", False)
+ self.assertEqual(len(self.userstore.items()),1)
+
+ def test_user_is_in_expert_group(self):
+ self.add_user("test_user", True)
+ self.assertEqual(self.userstore.expert("test_user"),True)
+
+ def test_user_is_not_in_expert_group(self):
+ self.add_user("test_user", False)
+ self.assertEqual(self.userstore.expert("test_user"),False)
+
+ def test_user_removal(self):
+ self.assertEqual(len(self.userstore.items()),0)
+ self.add_user("test_user", False)
+ self.assertEqual(len(self.userstore.items()),1)
+ self.userstore.remove("test_user")
+ self.assertEqual(len(self.userstore.items()),0)
+
+ def test_get_user_email_attribute(self):
+ self.add_user("test_user", False,"test@home")
+ self.assertEqual(self.userstore.attr("test_user","email"),"test@home")
+
+ def test_get_user(self):
+ test_user = self.add_user("test_user", False)
+ self.assertEqual(self.userstore.get("test_user"),test_user)
+
+ def test_get_all_users(self):
+ self.add_user("test_user1", False)
+ self.add_user("test_user2", False)
+ self.assertEqual(len(self.userstore.get_all()),2)
+
+ def add_user(self, test_username, add_to_expert_group, email=''):
+ test_user = self.create_user(test_username, email)
+ if add_to_expert_group:
+ test_user = self.add_user_to_expert_group(test_user)
+ self.userstore.set(test_username,test_user)
+ return test_user
+
+ def create_user(self, username, email=''):
+ test_user = User()
+ test_user["username"] = username
+ test_user["email"] = email
+ return test_user
+
+ def add_user_to_expert_group(self, user):
+ user["groups"] = ["expert"]
+ return user
+
+if __name__ == "__main__":
+ unittest.main()
\ No newline at end of file
diff --git a/tests/testdata/users.sqlite3 b/tests/testdata/users.sqlite3
new file mode 100644
index 0000000000000000000000000000000000000000..03782a7d7f4282049ab931c01f0df26b5534545f
GIT binary patch
literal 3072
zcmWFz^vNtqRY=P(%1ta$FlJz3U}R))P*7lCU`%FUU|@
zBSl{3KMYLF-3-j#%oouVjB-aqU^E0EA>hKuCN3_{m|2pTl#^Oql3xTNn4E)L9Yb6d
zLL8lZTou6L3L4p|l?o-P6(tI#d6|W!sX7W}i8){aO-&{?aa(alhRnQ_)QaN59ANH_
zPb@9T2lL~>+T#tu6ew@A@Ph1S0cP|*W(kNhM#<3-7!3hn2)v+qD70a*p$Ll@4TZQs
eW`pwoC+0^qv}V-k(GVC7fq@DEIW&v;5PSg0W;EIW
literal 0
HcmV?d00001