View | Details | Raw Unified | Return to bug 48341
Collapse All | Expand All

(-)a/services/univention-admin-diary/python/admindiary/de.po (+41 lines)
Line 0    Link Here 
1
# This file is auto-generated by the dh-umc tools and should not be edited!
2
msgid ""
3
msgstr ""
4
"Project-Id-Version: univention-admin-diary\n"
5
"Report-Msgid-Bugs-To: packages@univention.de\n"
6
"POT-Creation-Date: Mon, 10 Jan 2019 18:22:31 +0100\n"
7
"PO-Revision-Date: \n"
8
"Last-Translator: Univention GmbH <packages@univention.de>\n"
9
"Language-Team: Univention GmbH <packages@univention.de>\n"
10
"Language: de\n"
11
"MIME-Version: 1.0\n"
12
"Content-Type: text/plain; charset=UTF-8\n"
13
"Content-Transfer-Encoding: 8bit\n"
14
15
#: python/admindiary/events.py:53
16
#, python-format
17
msgid "User %s created"
18
msgstr "Benutzer %s angelegt"
19
20
#: python/admindiary/events.py:55
21
#, python-format
22
msgid "App %s: Start of %s"
23
msgstr "App %s: Start von %s"
24
25
#: python/admindiary/events.py:56
26
#, python-format
27
msgid "App %s (%s): Success"
28
msgstr "App %s (%s): Erfolg"
29
30
#: python/admindiary/events.py:57
31
#, python-format
32
msgid "App %s (%s): Failure. Error %s"
33
msgstr "App %s (%s): Fehlschlag. Fehler %s"
34
35
#: python/admindiary/events.py:59
36
msgid "Machine account password changed successfully"
37
msgstr "Maschinenpasswort erfolgreich geändert"
38
39
#: python/admindiary/events.py:60
40
msgid "Machine account password change failed"
41
msgstr "Änderung des Maschinenpassworts fehlgeschlagen"
(-)a/management/univention-appcenter/python/appcenter/actions/install_base.py (-3 / +3 lines)
 Lines 88-94   class InstallRemoveUpgrade(Register): Link Here 
88
		app = args.app
88
		app = args.app
89
		status = 200
89
		status = 200
90
		status_details = None
90
		status_details = None
91
		diary_id = write_event(APP_ACTION_START, [app, self.get_action_name()])
91
		context_id = write_event(APP_ACTION_START, [app, self.get_action_name()])
92
		try:
92
		try:
93
			action = self.get_action_name()
93
			action = self.get_action_name()
94
			self.log('Going to %s %s (%s)' % (action, app.name, app.version))
94
			self.log('Going to %s %s (%s)' % (action, app.name, app.version))
 Lines 149-157   class InstallRemoveUpgrade(Register): Link Here 
149
				pass
149
				pass
150
			else:
150
			else:
151
				if status == 200:
151
				if status == 200:
152
					write_event(APP_ACTION_SUCCESS, [app, self.get_action_name()], diary_id=diary_id)
152
					write_event(APP_ACTION_SUCCESS, [app, self.get_action_name()], context_id=context_id)
153
				else:
153
				else:
154
					write_event(APP_ACTION_FAILURE, [app, self.get_action_name(), status], diary_id=diary_id)
154
					write_event(APP_ACTION_FAILURE, [app, self.get_action_name(), status], context_id=context_id)
155
				if status != 200:
155
				if status != 200:
156
					self._revert(app, args)
156
					self._revert(app, args)
157
				if args.send_info:
157
				if args.send_info:
(-)a/services/univention-admin-diary/60univention-admin-diary-client.inst (-1 / +2 lines)
 Lines 44-51   set_admin_diary_backend() { Link Here 
44
	local cn_list
44
	local cn_list
45
	local fqdn_list
45
	local fqdn_list
46
46
47
	ldif=$(univention-ldapsearch univentionService="Admin Diary Backend" cn)
47
	ldif=$(univention-ldapsearch -LLL -o ldif-wrap=no univentionService="Admin Diary Backend" cn)
48
	cn_list=( "$(sed -n 's/^cn: //p' <<<"$ldif")" )
48
	cn_list=( "$(sed -n 's/^cn: //p' <<<"$ldif")" )
49
	[ -n "$cn_list" ] || return
49
	fqdn_list=( "${cn_list[@]/%/".$domainname"}" )
50
	fqdn_list=( "${cn_list[@]/%/".$domainname"}" )
50
51
51
	univention-config-registry set \
52
	univention-config-registry set \
(-)a/services/univention-admin-diary/debian/univention-admin-diary-backend.postinst (-17 / +31 lines)
 Lines 31-56    Link Here 
31
31
32
#DEBHELPER#
32
#DEBHELPER#
33
33
34
SECRET_FILE="/etc/admin-diary.secret"
34
eval "$(ucr shell admin/diary/db.*)"
35
if [ ! -e "$SECRET_FILE" ]; then
35
if [ -z "$admin_diary_dbhost" ] \
36
	touch "$SECRET_FILE"
36
	|| [ "$admin_diary_dbhost" = "localhost" ]; then
37
	chmod 0700 "$SECRET_FILE"
37
38
	PASSWORD="$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c20)"
38
	SECRET_FILE="/etc/admin-diary.secret"
39
	echo "$PASSWORD" > "$SECRET_FILE"
39
	if [ ! -e "$SECRET_FILE" ]; then
40
fi
40
		install -m 0700 "$SECRET_FILE"
41
		touch "$SECRET_FILE"
42
		chmod 0700 "$SECRET_FILE"
43
		PASSWORD="$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c20)"
44
		echo -n "$PASSWORD" > "$SECRET_FILE"
45
	fi
41
46
42
which psql
47
	if command -v psql >/dev/null; then
43
if [ "$?" -eq "0" ]; then
48
		ucr set admin/diary/dbms?postgresql
44
	ucr set admin/diary/dbms?postgresql
49
	else
45
else
50
		ucr set admin/diary/dbms?mysql
46
	ucr set admin/diary/dbms?mysql
51
	fi
52
elif [ -z "$admin_diary_dbms" ]; then
53
	echo "ERROR: admin/diary/dbhost is set in UCR but admin/diary/dbms is not" 2>&1
54
	exit 1
47
fi
55
fi
48
56
49
univention-config-registry set \
57
case "$1" in
50
	security/packetfilter/package/univention-admin-diary/tcp/10514/all=ACCEPT \
58
	configure)
51
	security/packetfilter/package/univention-admin-diary/tcp/10514/all/en="rsyslog relp+TLS"
59
		if [ -z "$2" ]; then  # Installation
52
invoke-rc.d univention-firewall restart
60
			univention-config-registry set \
61
				security/packetfilter/package/univention-admin-diary/tcp/10514/all=ACCEPT \
62
				security/packetfilter/package/univention-admin-diary/tcp/10514/all/en="rsyslog relp+TLS"
63
			invoke-rc.d univention-firewall restart
53
64
54
invoke-rc.d rsyslog try-restart
65
			invoke-rc.d rsyslog try-restart
66
		fi
67
		;;
68
esac
55
69
56
exit 0
70
exit 0
(-)a/services/univention-admin-diary/python/admindiary/__init__.py (-14 / +14 lines)
 Lines 45-51   class _ShortNameFormatter(logging.Formatter): Link Here 
45
		return super(_ShortNameFormatter, self).format(record)
45
		return super(_ShortNameFormatter, self).format(record)
46
46
47
47
48
def _setup_logger():
48
def _setup_logger(loglevel):
49
	base_logger = logging.getLogger('univention.admindiary')
49
	base_logger = logging.getLogger('univention.admindiary')
50
	if not _setup_logger._setup:
50
	if not _setup_logger._setup:
51
		log_format = '%(process)6d %(short_name)-12s %(asctime)s [%(levelname)8s]: %(message)s'
51
		log_format = '%(process)6d %(short_name)-12s %(asctime)s [%(levelname)8s]: %(message)s'
 Lines 54-79   def _setup_logger(): Link Here 
54
		handler = logging.FileHandler(LOG_FILE)
54
		handler = logging.FileHandler(LOG_FILE)
55
		handler.setFormatter(formatter)
55
		handler.setFormatter(formatter)
56
		base_logger.addHandler(handler)
56
		base_logger.addHandler(handler)
57
		base_logger.setLevel(logging.DEBUG)
57
		base_logger.setLevel(loglevel)
58
		_setup_logger._setup = True
58
		_setup_logger._setup = True
59
	return base_logger
59
	return base_logger
60
_setup_logger._setup = False
60
_setup_logger._setup = False
61
61
62
62
63
def get_logger(name):
63
def get_logger(name, loglevel=logging.WARNING):
64
	base_logger = _setup_logger()
64
	base_logger = _setup_logger(loglevel)
65
	return base_logger.getChild(name)
65
	return base_logger.getChild(name)
66
66
67
67
68
class DiaryEntry(object):
68
class DiaryEntry(object):
69
	def __init__(self, username, message, args, tags, diary_id, event_name):
69
	def __init__(self, username, message, args, tags, context_id, event_name):
70
		self.username = username
70
		self.username = username
71
		self.hostname = getfqdn()
71
		self.hostname = getfqdn()
72
		self.message = message
72
		self.message = message
73
		self.args = [str(arg) for arg in args]
73
		self.args = [str(arg) for arg in args]
74
		self.issued = datetime.now()
74
		self.timestamp = datetime.now()
75
		self.tags = tags
75
		self.tags = tags
76
		self.diary_id = diary_id
76
		self.context_id = context_id
77
		self.event_name = event_name
77
		self.event_name = event_name
78
78
79
	def assert_types(self):
79
	def assert_types(self):
 Lines 85-95   class DiaryEntry(object): Link Here 
85
			raise TypeError('Message has to be "string"')
85
			raise TypeError('Message has to be "string"')
86
		if not isinstance(self.args, list) or not all(isinstance(arg, basestring) for arg in self.args):
86
		if not isinstance(self.args, list) or not all(isinstance(arg, basestring) for arg in self.args):
87
			raise TypeError('Args have to be "list of string"')
87
			raise TypeError('Args have to be "list of string"')
88
		if not isinstance(self.issued, datetime):
88
		if not isinstance(self.timestamp, datetime):
89
			raise TypeError('Issued has to be "datetime"')
89
			raise TypeError('timestamp has to be "datetime"')
90
		if not isinstance(self.tags, list) or not all(isinstance(tag, basestring) for tag in self.tags):
90
		if not isinstance(self.tags, list) or not all(isinstance(tag, basestring) for tag in self.tags):
91
			raise TypeError('Tags have to be "list of string"')
91
			raise TypeError('Tags have to be "list of string"')
92
		if not isinstance(self.diary_id, basestring):
92
		if not isinstance(self.context_id, basestring):
93
			raise TypeError('Diary ID has to be "string"')
93
			raise TypeError('Diary ID has to be "string"')
94
		if not isinstance(self.event_name, basestring):
94
		if not isinstance(self.event_name, basestring):
95
			raise TypeError('Event name has to be "string"')
95
			raise TypeError('Event name has to be "string"')
 Lines 100-108   class DiaryEntry(object): Link Here 
100
			'hostname': self.hostname,
100
			'hostname': self.hostname,
101
			'message': self.message,
101
			'message': self.message,
102
			'args': self.args,
102
			'args': self.args,
103
			'issued': self.issued.strftime('%Y-%m-%d %H:%M:%S%z'),
103
			'timestamp': self.timestamp.strftime('%Y-%m-%d %H:%M:%S%z'),
104
			'tags': self.tags,
104
			'tags': self.tags,
105
			'diary_id': self.diary_id,
105
			'context_id': self.context_id,
106
			'event': self.event_name,
106
			'event': self.event_name,
107
			}
107
			}
108
		return json.dumps(attrs)
108
		return json.dumps(attrs)
 Lines 110-117   class DiaryEntry(object): Link Here 
110
	@classmethod
110
	@classmethod
111
	def from_json(cls, body):
111
	def from_json(cls, body):
112
		json_body = json.loads(body)
112
		json_body = json.loads(body)
113
		entry = cls(json_body['username'], json_body['message'], json_body['args'], json_body['tags'], json_body['diary_id'], json_body['event'])
113
		entry = cls(json_body['username'], json_body['message'], json_body['args'], json_body['tags'], json_body['context_id'], json_body['event'])
114
		entry.issued = datetime.strptime(json_body['issued'], '%Y-%m-%d %H:%M:%S')
114
		entry.timestamp = datetime.strptime(json_body['timestamp'], '%Y-%m-%d %H:%M:%S')
115
		entry.hostname = json_body['hostname']
115
		entry.hostname = json_body['hostname']
116
		entry.assert_types()
116
		entry.assert_types()
117
		return entry
117
		return entry
(-)a/services/univention-admin-diary/python/admindiary/backend.py (-8 / +9 lines)
 Lines 42-56   ucr.load() Link Here 
42
password = open('/etc/admin-diary.secret').read().strip()
42
password = open('/etc/admin-diary.secret').read().strip()
43
43
44
dbms = ucr.get('admin/diary/dbms')
44
dbms = ucr.get('admin/diary/dbms')
45
dbhost = ucr.get('admin/diary/dbhost', 'localhost')
45
46
46
get_logger = partial(get_logger, 'backend')
47
get_logger = partial(get_logger, 'backend')
47
48
48
@contextmanager
49
@contextmanager
49
def connection(module):
50
def connection(module):
50
	if dbms == 'mysql':
51
	if dbms == 'mysql':
51
		conn = module.connect(db='admindiary', user='admindiary', host='localhost', passwd=password)
52
		conn = module.connect(db='admindiary', user='admindiary', host=dbhost, passwd=password)
52
	elif dbms == 'postgresql':
53
	elif dbms == 'postgresql':
53
		conn = module.connect(dbname='admindiary', user='admindiary', host='localhost', password=password)
54
		conn = module.connect(dbname='admindiary', user='admindiary', host=dbhost, password=password)
54
	yield conn
55
	yield conn
55
	conn.commit()
56
	conn.commit()
56
	conn.close()
57
	conn.close()
 Lines 68-79   if ucr.get('admin/diary/dbms') == 'postgresql': Link Here 
68
69
69
	def _postgresql_add(entry):
70
	def _postgresql_add(entry):
70
		with cursor(psycopg2) as cur:
71
		with cursor(psycopg2) as cur:
71
			cur.execute("INSERT INTO entries (username, hostname, message, args, issued, tags, diary_id, event_name) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)", (entry.username, entry.hostname, entry.message, entry.args, entry.issued, entry.tags, entry.diary_id, entry.event_name))
72
			cur.execute("INSERT INTO entries (username, hostname, message, args, timestamp, tags, context_id, event_name) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)", (entry.username, entry.hostname, entry.message, entry.args, entry.timestamp, entry.tags, entry.context_id, entry.event_name))
72
		get_logger().info('Successfully added %s to postgresql. (%s)' % (entry.diary_id, entry.event_name))
73
		get_logger().info('Successfully added %s to postgresql. (%s)' % (entry.context_id, entry.event_name))
73
74
74
	def _postgresql_query():
75
	def _postgresql_query():
75
		with cursor(psycopg2) as cur:
76
		with cursor(psycopg2) as cur:
76
			args = ['id', 'username', 'hostname', 'message', 'args', 'issued', 'tags', 'diary_id', 'event_name']
77
			args = ['id', 'username', 'hostname', 'message', 'args', 'timestamp', 'tags', 'context_id', 'event_name']
77
			cur.execute("SELECT %s FROM entries" % ', '.join(args))
78
			cur.execute("SELECT %s FROM entries" % ', '.join(args))
78
			rows = cur.fetchall()
79
			rows = cur.fetchall()
79
			res = [dict(zip(args, row)) for row in rows]
80
			res = [dict(zip(args, row)) for row in rows]
 Lines 90-106   elif ucr.get('admin/diary/dbms') == 'mysql': Link Here 
90
91
91
	def _mysql_add(entry):
92
	def _mysql_add(entry):
92
		with cursor(MySQLdb) as cur:
93
		with cursor(MySQLdb) as cur:
93
			cur.execute("INSERT INTO entries (username, hostname, message, issued, diary_id, event_name) VALUES (%s, %s, %s, %s, %s, %s)", (entry.username, entry.hostname, entry.message, entry.issued, entry.diary_id, entry.event_name))
94
			cur.execute("INSERT INTO entries (username, hostname, message, timestamp, context_id, event_name) VALUES (%s, %s, %s, %s, %s, %s)", (entry.username, entry.hostname, entry.message, entry.timestamp, entry.context_id, entry.event_name))
94
			entry_id = cur.lastrowid
95
			entry_id = cur.lastrowid
95
			for arg in entry.args:
96
			for arg in entry.args:
96
				cur.execute("INSERT INTO arguments (log_entry_id, arg) VALUES (%s, %s)", (entry_id, arg))
97
				cur.execute("INSERT INTO arguments (log_entry_id, arg) VALUES (%s, %s)", (entry_id, arg))
97
			for tag in entry.tags:
98
			for tag in entry.tags:
98
				cur.execute("INSERT INTO tags (log_entry_id, tag) VALUES (%s, %s)", (entry_id, tag))
99
				cur.execute("INSERT INTO tags (log_entry_id, tag) VALUES (%s, %s)", (entry_id, tag))
99
		get_logger().info('Successfully added %s to mysql. (%s)' % (entry.diary_id, entry.event_name))
100
		get_logger().info('Successfully added %s to mysql. (%s)' % (entry.context_id, entry.event_name))
100
101
101
	def _mysql_query():
102
	def _mysql_query():
102
		with cursor(MySQLdb) as cur:
103
		with cursor(MySQLdb) as cur:
103
			args = ['id', 'username', 'hostname', 'message', 'issued', 'diary_id', 'event_name']
104
			args = ['id', 'username', 'hostname', 'message', 'timestamp', 'context_id', 'event_name']
104
			cur.execute("SELECT %s FROM entries" % ', '.join(args))
105
			cur.execute("SELECT %s FROM entries" % ', '.join(args))
105
			rows = cur.fetchall()
106
			rows = cur.fetchall()
106
			res = [dict(zip(args, row)) for row in rows]
107
			res = [dict(zip(args, row)) for row in rows]
(-)a/services/univention-admin-diary/python/admindiary/client.py (-15 / +15 lines)
 Lines 39-45   from functools import partial, wraps Link Here 
39
get_logger = partial(get_logger, 'client')
39
get_logger = partial(get_logger, 'client')
40
40
41
41
42
def safe(f):
42
def exceptionlogging(f):
43
	@wraps(f)
43
	@wraps(f)
44
	def wrapper(*args, **kwds):
44
	def wrapper(*args, **kwds):
45
		try:
45
		try:
 Lines 63-103   class RsyslogEmitter(object): Link Here 
63
emitter = RsyslogEmitter()
63
emitter = RsyslogEmitter()
64
64
65
65
66
@safe
66
@exceptionlogging
67
def add_comment(message, diary_id, username=None):
67
def add_comment(message, context_id, username=None):
68
	event = Event('COMMENT', message)
68
	event = Event('COMMENT', message)
69
	return write_event(event, username=username, diary_id=diary_id)
69
	return write_event(event, username=username, context_id=context_id)
70
70
71
71
72
@safe
72
@exceptionlogging
73
def write_event(event, args=None, username=None, diary_id=None):
73
def write_event(event, args=None, username=None, context_id=None):
74
	args = args or []
74
	args = args or []
75
	if not isinstance(args, (list, tuple)):
75
	if not isinstance(args, (list, tuple)):
76
		raise TypeError('"args" must be a list')
76
		raise TypeError('"args" must be a list')
77
	if len(args) != len(event.args):
77
	if len(args) != len(event.args):
78
		raise ValueError('Writing "%s" needs %d argument(s) (%s). %d given' % (event.message, len(event.args), ', '.join(event.args), len(args)))
78
		raise ValueError('Writing "%s" needs %d argument(s) (%s). %d given' % (event.message, len(event.args), ', '.join(event.args), len(args)))
79
	return write(event.message, args, username, event.tags, diary_id, event.name)
79
	return write(event.message, args, username, event.tags, context_id, event.name)
80
80
81
81
82
@safe
82
@exceptionlogging
83
def write(message, args=None, username=None, tags=None, diary_id=None, event_name=None):
83
def write(message, args=None, username=None, tags=None, context_id=None, event_name=None):
84
	if username is None:
84
	if username is None:
85
		username = getuser()
85
		username = getuser()
86
	if args is None:
86
	if args is None:
87
		args = []
87
		args = []
88
	if tags is None:
88
	if tags is None:
89
		tags = []
89
		tags = []
90
	if diary_id is None:
90
	if context_id is None:
91
		diary_id = str(uuid.uuid4())
91
		context_id = str(uuid.uuid4())
92
	if event_name is None:
92
	if event_name is None:
93
		event_name = 'CUSTOM'
93
		event_name = 'CUSTOM'
94
	entry = DiaryEntry(username, message, args, tags, diary_id, event_name)
94
	entry = DiaryEntry(username, message, args, tags, context_id, event_name)
95
	return write_entry(entry)
95
	return write_entry(entry)
96
96
97
97
98
@safe
98
@exceptionlogging
99
def write_entry(entry):
99
def write_entry(entry):
100
	body = entry.to_json()
100
	body = entry.to_json()
101
	emitter.emit(body)
101
	emitter.emit(body)
102
	get_logger().info('Successfully wrote %s. (%s)' % (entry.diary_id, entry.event_name))
102
	get_logger().info('Successfully wrote %s. (%s)' % (entry.context_id, entry.event_name))
103
	return entry.diary_id
103
	return entry.context_id
(-)a/services/univention-admin-diary/python/admindiary/events.py (-6 / +10 lines)
 Lines 46-56   class Event(object): Link Here 
46
		self.tags = tags or []
46
		self.tags = tags or []
47
		self._all_events[self.name] = self
47
		self._all_events[self.name] = self
48
48
49
USER_CREATED = Event('USER_CREATED', 'User %s created', ['username'])
49
def _(msg):
50
	"""dummy for xgettext"""
51
	return msg
50
52
51
APP_ACTION_START = Event('APP_ACTION_START', 'App %s: Starting to %s', ['app', 'action'])
53
USER_CREATED = Event('USER_CREATED', _('User %s created'), ['username'])
52
APP_ACTION_SUCCESS = Event('APP_ACTION_SUCCESS', 'App %s (%s): Success', ['app', 'action'])
53
APP_ACTION_FAILURE = Event('APP_ACTION_FAILURE', 'App %s (%s): Failure. Error %s', ['app', 'action', 'error_code'], tags=['error'])
54
54
55
SERVER_PASSWORD_CHANGED = Event('SERVER_PASSWORD_CHANGED', 'Machine account password changed successfully')
55
APP_ACTION_START = Event('APP_ACTION_START', _('App %s: Start of %s'), ['app', 'action'])
56
SERVER_PASSWORD_CHANGED_FAILED = Event('SERVER_PASSWORD_CHANGED_FAILED', 'Machine account password change failed!', tags=['error'])
56
APP_ACTION_SUCCESS = Event('APP_ACTION_SUCCESS', _('App %s (%s): Success'), ['app', 'action'])
57
APP_ACTION_FAILURE = Event('APP_ACTION_FAILURE', _('App %s (%s): Failure. Error %s'), ['app', 'action', 'error_code'], tags=['error'])
58
59
SERVER_PASSWORD_CHANGED = Event('SERVER_PASSWORD_CHANGED', _('Machine account password changed successfully'))
60
SERVER_PASSWORD_CHANGED_FAILED = Event('SERVER_PASSWORD_CHANGED_FAILED', _('Machine account password change failed'), tags=['error'])
(-)a/services/univention-admin-diary/setup-dbms (-4 / +4 lines)
 Lines 40-48   if [ "$db_backend" = "postgresql" ]; then Link Here 
40
		hostname VARCHAR NOT NULL,
40
		hostname VARCHAR NOT NULL,
41
		message TEXT NOT NULL,
41
		message TEXT NOT NULL,
42
		args VARCHAR[],
42
		args VARCHAR[],
43
		issued TIMESTAMPTZ NOT NULL,
43
		timestamp TIMESTAMPTZ NOT NULL,
44
		tags VARCHAR[],
44
		tags VARCHAR[],
45
		diary_id VARCHAR NOT NULL,
45
		context_id VARCHAR NOT NULL,
46
		event_name VARCHAR NOT NULL,
46
		event_name VARCHAR NOT NULL,
47
		created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
47
		created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
48
	);
48
	);
 Lines 55-62   elif [ "$db_backend" = "mysql" ]; then Link Here 
55
		username VARCHAR(512) NOT NULL,
55
		username VARCHAR(512) NOT NULL,
56
		hostname VARCHAR(512) NOT NULL,
56
		hostname VARCHAR(512) NOT NULL,
57
		message TEXT NOT NULL,
57
		message TEXT NOT NULL,
58
		issued TIMESTAMP NOT NULL,
58
		timestamp TIMESTAMP NOT NULL,
59
		diary_id VARCHAR(512) NOT NULL,
59
		context_id VARCHAR(512) NOT NULL,
60
		event_name VARCHAR(512) NOT NULL,
60
		event_name VARCHAR(512) NOT NULL,
61
		created_at TIMESTAMP NOT NULL DEFAULT NOW(),
61
		created_at TIMESTAMP NOT NULL DEFAULT NOW(),
62
		PRIMARY KEY(id)
62
		PRIMARY KEY(id)
(-)a/services/univention-admin-diary/univention-admin-diary-entry-create (-6 / +6 lines)
 Lines 45-64   def main(): Link Here 
45
	parser.add_argument('-u', '--username', help='Username that issues the diary entry')
45
	parser.add_argument('-u', '--username', help='Username that issues the diary entry')
46
	parser.add_argument('-t', '--tag', action='append', help='Tags added to the diary entry')
46
	parser.add_argument('-t', '--tag', action='append', help='Tags added to the diary entry')
47
	parser.add_argument('-a', '--arg', action='append', help='Argument used in message')
47
	parser.add_argument('-a', '--arg', action='append', help='Argument used in message')
48
	parser.add_argument('--event', choices=Event.names(), help='Choose one from this convenience list instead of giving TAG and <message>')
48
	parser.add_argument('--event', choices=Event.names(), help='Choose one from this standard list instead of giving TAG and <message>')
49
	parser.add_argument('--diary-id', help='May be given to ammend an existing diary entry, effectively grouping those together. The DIARY_ID is also returned by this program')
49
	parser.add_argument('--context-id', help='May be given to ammend an existing diary entry, effectively grouping those together. The CONTEXT_ID is also returned by this program')
50
	parser.add_argument('message', nargs=REMAINDER, help='The message')
50
	parser.add_argument('message', nargs=REMAINDER, help='The message')
51
	args = parser.parse_args()
51
	args = parser.parse_args()
52
	if args.event:
52
	if args.event:
53
		event = Event.get(args.event)
53
		event = Event.get(args.event)
54
		diary_id = write_event(event, args.arg, args.username, args.diary_id)
54
		context_id = write_event(event, args.arg, args.username, args.context_id)
55
		if diary_id is not None:
55
		if context_id is not None:
56
			print diary_id
56
			print context_id
57
		else:
57
		else:
58
			print >> sys.stderr, 'Could not write event'
58
			print >> sys.stderr, 'Could not write event'
59
			sys.exit(1)
59
			sys.exit(1)
60
	else:
60
	else:
61
		print write(' '.join(args.message), args.arg, args.username, args.tag, args.diary_id)
61
		print write(' '.join(args.message), args.arg, args.username, args.tag, args.context_id)
62
62
63
if __name__ == '__main__':
63
if __name__ == '__main__':
64
	main()
64
	main()

Return to bug 48341