Refactoring

develop 3.4.1.1
Mike Khiretskiy 9 years ago
parent 943ae97e3a
commit 4f4d4ce2cf

@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright 2008-2012 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2008-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,7 +15,9 @@
# limitations under the License.
from PySide import QtCore, QtGui
import os,sys
import os
import re
class ImageViewer(QtGui.QMainWindow):
def __init__(self):
@ -28,25 +30,27 @@ class ImageViewer(QtGui.QMainWindow):
screen = QtGui.QDesktopWidget().screenGeometry()
self.setGeometry(screen)
self.open('/usr/share/wallpapers/dm-background.png') or \
self.open('/usr/share/apps/ksplash/Themes/CalculateSplashEn/'
'400x300/background.png') or \
self.setBackground()
if not any(self.open(x) for x in
('/usr/share/wallpapers/dm-background.png',
'/usr/share/apps/ksplash/Themes/CalculateSplashEn/'
'400x300/background.png')):
self.set_background()
def selectColor(self):
@staticmethod
def select_color():
try:
if filter(re.compile(r"(cld|cldx|cldg|cmc|cls)-themes-12").search,
os.listdir('/var/db/pkg/media-gfx')):
os.listdir('/var/db/pkg/media-gfx')):
return "#73a363"
except:
except OSError:
pass
return '#30648b'
def setBackground(self):
self.setStyleSheet("background-color: %s"%self.selectColor())
def set_background(self):
self.setStyleSheet("background-color: %s" % self.select_color())
def open(self,fileName):
image = QtGui.QImage(fileName)
def open(self, fn):
image = QtGui.QImage(fn)
if image.isNull():
return False
@ -55,8 +59,10 @@ class ImageViewer(QtGui.QMainWindow):
self.imageLabel.adjustSize()
return True
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
imageViewer = ImageViewer()
imageViewer.show()

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,14 +15,15 @@
# limitations under the License.
__app__ = 'calculate-desktop'
__version__ = '3.1.8'
__version__ = '3.4.2'
import os
import sys
from calculate.lib.datavars import DataVars
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
setLocalTranslate('cl_desktop3', sys.modules[__name__])
class DataVarsDesktop(DataVars):
"""Variable class for desktop package"""

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2010-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2010-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -16,51 +16,49 @@
import os
from os import path
import re
import sys
import pwd
import time
import traceback
from calculate.core.server.core_interfaces import MethodsInterface
from calculate.desktop._cl_keys import getKey, clearKey
from datavars import DataVarsDesktop, DataVars, __version__,__app__
from calculate.desktop._cl_keys import getKey
from calculate.lib.cl_template import (Template, ProgressTemplate,
TemplatesError,templateFunction,iniParser)
from calculate.lib.utils.files import (runOsCommand, isMount,process,
getRunCommands,STDOUT,childMounts,getLoopFromPath,
getMdRaidDevices,listDirectory,removeDir,
makeDirectory)
from calculate.lib.utils.common import (getpathenv,appendProgramToEnvFile,
removeProgramToEnvFile,mountEcryptfs,
CommonError, isBootstrapDataOnly)
from calculate.lib.utils.files import (isMount, process,
getRunCommands, STDOUT, childMounts,
getLoopFromPath,
getMdRaidDevices, listDirectory,
removeDir,
makeDirectory, getProgPath)
from calculate.lib.utils.common import (mountEcryptfs,
CommonError, isBootstrapDataOnly)
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_desktop3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
from itertools import ifilter
import tarfile
import tempfile
import shutil
from itertools import count
class DesktopError(Exception):
"""Desktop Error"""
class Desktop:
class Desktop(MethodsInterface):
"""
Модуль для настройки пользовательского сеанса и выполнения
принудительного выхода из X сессии пользователя
"""
def __init__(self):
self.homeDir = ""
self.clTempl = None
self.clVars = None
def createCryptDir(self,userName,uid,gid,userDir,recreateOnError=False):
def createCryptDir(self, userName, uid, gid, userDir,
recreateOnError=False):
"""
Создать шифрование домашней директории, или подключить существующую
@ -73,20 +71,21 @@ class Desktop:
# проверить наличие пароля в ключах ядра
if not userPwd or userPwd == "XXXXXXXX":
raise DesktopError(_("User password not found"))
ecryptfsPath = path.join('/home/.ecryptfs',userName)
ecryptfsPath = path.join('/home/.ecryptfs', userName)
# если шифрование уже используется
if path.exists(ecryptfsPath):
for d in (".ecryptfs",".Private"):
source,target = path.join(ecryptfsPath,d),path.join(userDir,d)
for d in (".ecryptfs", ".Private"):
source, target = path.join(ecryptfsPath, d), path.join(userDir,
d)
if not path.lexists(target):
os.symlink(source,target)
os.symlink(source, target)
# попытаться подключить шифрованные данные
try:
if not mountEcryptfs(userName,userPwd,userDir):
if not mountEcryptfs(userName, userPwd, userDir):
error = _("Failed to mount ecrypted data")
except CommonError as e:
error = (_("Failed to mount ecrypted data")+
_(": ")+'":%s"'%str(e))
error = (_("Failed to mount ecrypted data") +
_(": ") + '":%s"' % str(e))
# если при подключении произошли ошибки
if error:
# заархивировать текущий профиль и удалить его
@ -94,17 +93,17 @@ class Desktop:
self.printSUCCESS(_("Recovering encrypted data"))
if self.getMountUserPaths(userDir):
raise DesktopError(_("Failed to encrypt the directory"))
for source in (userDir,ecryptfsPath):
for source in (userDir, ecryptfsPath):
if path.exists(source):
if listDirectory(source):
target = source+".bak"
target = source + ".bak"
newtarget = target
if path.exists(target):
removeDir(target)
os.rename(source,newtarget)
os.rename(source, newtarget)
else:
os.rmdir(source)
self.createUserDir(userName,uid,gid,userDir)
self.createUserDir(userName, uid, gid, userDir)
# ошибка создания шифрования
else:
raise DesktopError(error)
@ -116,39 +115,40 @@ class Desktop:
if isBootstrapDataOnly(userDir):
if childMounts(userDir):
raise DesktopError(
_("Failed to create an encrypted user profile")+
_(": ")+
_("Failed to create an encrypted user profile") +
_(": ") +
_("The home directory contains mount points"))
# поместить данные во временный tarfile
calculateName = ".calculate"
calculatePath = path.join(userDir,calculateName)
calculatePath = path.join(userDir, calculateName)
tf = tempfile.TemporaryFile()
with tarfile.open(fileobj=tf,mode='w:') as tarf:
tarf.add(calculatePath,calculateName)
with tarfile.open(fileobj=tf, mode='w:') as tarf:
tarf.add(calculatePath, calculateName)
tf.flush()
tf.seek(0)
# удалить эти данные
shutil.rmtree(calculatePath)
# создать шифрованные данные
e = process('/usr/bin/ecryptfs-setup-private','-u',userName,
'-b','-l',userPwd,stderr=STDOUT)
e = process('/usr/bin/ecryptfs-setup-private', '-u', userName,
'-b', '-l', userPwd, stderr=STDOUT)
if e.failed():
raise DesktopError(e.read())
# если были данные от бутстрапа, то распаковать их
if tf:
with tarfile.open(fileobj=tf,mode='r:') as tarf:
with tarfile.open(fileobj=tf, mode='r:') as tarf:
tarf.extractall(userDir)
except Exception as e:
# в случае ошибки сохраняем архив (с данными bootstrap)
# из памяти в файловую систему
if tf:
tf.seek(0)
bakArchName = path.join(userDir,".calculate.tar.bz2")
with open(bakArchName,'w') as f:
bakArchName = path.join(userDir, ".calculate.tar.bz2")
with open(bakArchName, 'w') as f:
f.write(tf.read())
raise DesktopError(str(e)+
_("Failed to create an encrypted user profile"))
raise DesktopError(str(e) +
_(
"Failed to create an encrypted user profile"))
finally:
if tf:
tf.close()
@ -161,11 +161,11 @@ class Desktop:
if not path.exists(userDir):
os.makedirs(userDir)
if mode:
os.chmod(userDir,mode)
os.chown(userDir,uid,gid)
os.chmod(userDir, mode)
os.chown(userDir, uid, gid)
return True
else:
raise DesktopError(_("Path %s exists") %userDir)
raise DesktopError(_("Path %s exists") % userDir)
def umountUserRes(self, *umountPaths):
"""
@ -183,66 +183,53 @@ class Desktop:
Found user resources
"""
if not homeDir:
userName = self.clVars.Get("ur_login")
self.clVars.Get("ur_login")
homeDir = self.clVars.Get("ur_home_path")
if not homeDir:
raise DesktopError(_("Failed to determine the home directory"))
dirStart, dirEnd = path.split(homeDir)
mountProfileDir = path.join(dirStart, ".%s" %dirEnd)
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd)
return filter(lambda x: x.startswith(homeDir) or\
x.startswith(mountProfileDir) or\
x.startswith(mountRemoteProfileDir),
map(lambda x: x.split(" ")[1],\
mountProfileDir = path.join(dirStart, ".%s" % dirEnd)
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" % dirEnd)
return filter(lambda x: x.startswith(homeDir) or
x.startswith(mountProfileDir) or
x.startswith(mountRemoteProfileDir),
map(lambda x: x.split(" ")[1],
open("/proc/mounts").readlines()))
def execProg(self, cmdStrProg, inStr=False, envProg={}):
"""
Exec external program
"""
env_path = {"PATH":getpathenv()}
env = {}
env.update(os.environ.items() + env_path.items() + envProg.items())
retCode,programOut = runOsCommand(cmdStrProg,in_str=inStr,env_dict=env)
if not retCode:
return programOut
return False
def umountSleepPath(self, rpath):
"""
Отмонтировать указанный путь, а также отключить используемые
в этом пути loop устройства и raid
"""
# check for mount
umount_cmd = getProgPath('/bin/umount')
fuser_cmd = getProgPath("/bin/fuser")
loops = getLoopFromPath(rpath)
if loops:
setLoops = set(map(lambda x:x.partition('/dev/')[2],loops))
setLoops = set(map(lambda x: x.partition('/dev/')[2], loops))
mdInfo = getMdRaidDevices()
for k,v in mdInfo.items():
for k, v in mdInfo.items():
if setLoops & set(v):
self.umountSleepPath('/dev/%s'%k)
process('/sbin/mdadm','--stop','/dev/%s'%k).success()
self.umountSleepPath('/dev/%s' % k)
process('/sbin/mdadm', '--stop', '/dev/%s' % k).success()
for loop in loops:
self.umountSleepPath(loop)
process('/sbin/losetup','-d',loop).success()
process('/sbin/losetup', '-d', loop).success()
if isMount(rpath):
for waittime in [0,0.5,1,2]:
for waittime in [0, 0.5, 1, 2]:
time.sleep(waittime)
if not self.execProg("umount %s"%rpath) is False \
or not isMount(rpath):
if not isMount(rpath):
return True
self.execProg("fuser -km %s"%rpath)
process(umount_cmd, rpath).success()
if not isMount(rpath):
return True
process(fuser_cmd, "-km", rpath).success()
for waittime in [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]:
time.sleep(waittime)
if not self.execProg("umount %s"%rpath) is False \
or not isMount(rpath):
if not isMount(rpath):
return True
self.execProg("umount -l %s"%rpath)
if not isMount(rpath):
return True
process(umount_cmd, "-l", rpath).success()
else:
if isMount(rpath):
self.printERROR(_("Failed to unmount directory %s")%rpath)
self.printERROR(_("Failed to unmount directory %s") % rpath)
return False
return True
@ -257,9 +244,9 @@ class Desktop:
fastlogin_user = path.join(fastlogin, urLogin)
if not path.exists(fastlogin_user):
try:
open(fastlogin_user,'w').close()
open(fastlogin_user, 'w').close()
return True
except:
except IOError:
self.printWARNING(_("Failed to create the fastlogin mark file"))
return False
@ -268,24 +255,25 @@ class Desktop:
Выполнить logout пользователя через dbus
"""
display = self.clVars.Select('cl_desktop_online_display',
where='cl_desktop_online_user',eq=urLogin,limit=1)
where='cl_desktop_online_user', eq=urLogin,
limit=1)
session = self.clVars.Get('cl_desktop_xsession')
if session == 'xfce':
logoutCommand = "/usr/bin/qdbus org.xfce.SessionManager " \
"/org/xfce/SessionManager Logout False False"
"/org/xfce/SessionManager Logout False False"
elif session == 'kde':
logoutCommand = "/usr/bin/kquitapp ksmserver"
elif session == 'gnome':
logoutCommand = "/usr/bin/qdbus org.gnome.SessionManager " \
"/org/gnome/SessionManager Logout 1"
"/org/gnome/SessionManager Logout 1"
else:
raise DesktopError(_("Unable to detect the X session"))
if process("su",urLogin,"-c",
("DISPLAY=:%s "%display)+logoutCommand).failed():
if process("su", urLogin, "-c",
("DISPLAY=:%s " % display) + logoutCommand).failed():
raise DesktopError(_("Unable to send the logout command"))
return True
def waitLogout(self,urLogin,waitTime,postWaitTime=5):
def waitLogout(self, urLogin, waitTime, postWaitTime=5):
"""
Ожидать завершения пользовательского сеанса
@ -294,24 +282,24 @@ class Desktop:
waitTime: время ожидания завершения сеанса
"""
if filter(lambda x: "xdm/xdm\x00--logout" in x,
getRunCommands()):
for i in range(0,waitTime):
getRunCommands()):
for i in range(0, waitTime):
if not filter(lambda x: "xdm/xdm\x00--logout" in x,
getRunCommands()):
getRunCommands()):
return True
time.sleep(1)
else:
raise DesktopError(_("Unable to wait for completion "
"of the user logout"))
for wait in range(0,5):
for wait in range(0, 5):
self.clVars.Invalidate('cl_desktop_online_data')
if not urLogin in self.clVars.Get('cl_desktop_online_user'):
if urLogin not in self.clVars.Get('cl_desktop_online_user'):
return True
time.sleep(1)
else:
return False
def prepareFace(self,ur_home_path):
def prepareFace(self, ur_home_path):
"""Подготовить каталог пользователя с шифрованием для работы с .face
Для шифрованных профилей в корне домашней директории
@ -325,7 +313,7 @@ class Desktop:
True/False в зависимости от успешности
"""
if path.exists(ur_home_path):
symlink_path = path.join(ur_home_path,'.face')
symlink_path = path.join(ur_home_path, '.face')
if not path.lexists(symlink_path):
os.symlink('.ecryptfs/.face', symlink_path)
return True

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2010-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2010-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -16,21 +16,23 @@
import sys
from os import path
from calculate.core.server.func import Action,Tasks
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.core.server.func import Action, Tasks
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError, isMount
from calculate.desktop.desktop import DesktopError
from calculate.lib.cl_template import TemplatesError
setLocalTranslate('cl_desktop3',sys.modules[__name__])
_ = lambda x: x
setLocalTranslate('cl_desktop3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClDesktopLogoutAction(Action):
"""
Вывести пользователя из X сессии
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,DesktopError,TemplatesError)
native_error = (FilesError, DesktopError, TemplatesError)
successMessage = __("User logged out!")
failedMessage = __("Unable to log out")
@ -38,20 +40,21 @@ class ClDesktopLogoutAction(Action):
# список задач для действия
tasks = [
{'name':'user_logout',
'method':'Desktop.userLogout(cl_desktop_login)',
{'name': 'user_logout',
'method': 'Desktop.userLogout(cl_desktop_login)',
},
{'name':'wait_logout',
'message':__("Waiting for the logout"),
'method':'Desktop.waitLogout(cl_desktop_login,300)'}
]
{'name': 'wait_logout',
'message': __("Waiting for the logout"),
'method': 'Desktop.waitLogout(cl_desktop_login,300)'}
]
class ClDesktopAction(Action):
"""
Настроить пользовательский профиль
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,DesktopError,TemplatesError)
native_error = (FilesError, DesktopError, TemplatesError)
successMessage = __("User account {ur_login} has been "
"successfully configured")
@ -60,50 +63,51 @@ class ClDesktopAction(Action):
# список задач для действия
tasks = [
# создать домашниюю директорию
{'name':'create_home',
'message':__("Creating the home directory for {ur_login}"),
'method':'Desktop.createUserDir(ur_login,ur_uid,ur_gid,ur_home_path)',
'condition':lambda dv:not path.exists(dv.Get('ur_home_path'))
# создать домашниюю директорию
{'name': 'create_home',
'message': __("Creating the home directory for {ur_login}"),
'method': 'Desktop.createUserDir(ur_login,ur_uid,ur_gid,ur_home_path)',
'condition': lambda dv: not path.exists(dv.Get('ur_home_path'))
},
# используется ли шифрование
{'name':'crypt',
'condition':lambda dv:(not isMount(dv.Get('ur_home_path')) and \
dv.Get('ur_home_crypt_set') == 'on' and
(not dv.isModuleInstalled("install") or
dv.Get('install.cl_autologin') != dv.Get('ur_login')))
# используется ли шифрование
{'name': 'crypt',
'condition': lambda dv: (not isMount(dv.Get('ur_home_path')) and
dv.Get('ur_home_crypt_set') == 'on' and
(not dv.isModuleInstalled("install") or
dv.Get('install.cl_autologin') != dv.Get(
'ur_login')))
},
# подготовить шифрованный профиль пользователя для работы с .icon
{'name':'crypt:prepare_icon',
'method':'Desktop.prepareFace(ur_home_path)',
'condition':lambda Get:Get('ur_domain_set') == 'off'
# подготовить шифрованный профиль пользователя для работы с .icon
{'name': 'crypt:prepare_icon',
'method': 'Desktop.prepareFace(ur_home_path)',
'condition': lambda Get: Get('ur_domain_set') == 'off'
},
# подключить шифрованные данные
{'name':'crypt:ecryptfs',
'message':__("Mounting encrypted data"),
'method':'Desktop.createCryptDir(ur_login,ur_uid,ur_gid,'
'ur_home_path,False)'
# подключить шифрованные данные
{'name': 'crypt:ecryptfs',
'message': __("Mounting encrypted data"),
'method': 'Desktop.createCryptDir(ur_login,ur_uid,ur_gid,'
'ur_home_path,False)'
},
# настроить пользовательских профиль шаблонами
{'name':'user_profile',
'message':__("Setting up the user profile"),
'method':'Desktop.applyTemplates(None,False,'\
# настроить пользовательских профиль шаблонами
{'name': 'user_profile',
'message': __("Setting up the user profile"),
'method': 'Desktop.applyTemplates(None,False,'
'False,None)',
'condition':lambda Get: Get('cl_desktop_force_setup_set') == 'on' or \
Get('cl_desktop_update_profile_set') == 'on'
'condition': lambda Get: (Get('cl_desktop_force_setup_set') == 'on' or
Get('cl_desktop_update_profile_set') == 'on')
},
{'name':'fast_login',
'method':'Desktop.setFastlogin(ur_login)',
'essential':False,
'condition':lambda Get: Get('ur_domain_set') == 'off'
{'name': 'fast_login',
'method': 'Desktop.setFastlogin(ur_login)',
'essential': False,
'condition': lambda Get: Get('ur_domain_set') == 'off'
},
# отключить ресурсы подключенные в каталоге пользователя
{'name':'umount_userres',
'message': _("Unmouning user resources"),
'method':'Desktop.umountUserRes(ur_mount_dirs)',
'condition': lambda dv:dv.Get('ur_mount_dirs'),
'depend': Tasks.failed()},
{'name':'ecryptfs:umount_homedir',
'method':'Desktop.umountUserRes(ur_home_path)',
'depend': Tasks.failed()}
]
# отключить ресурсы подключенные в каталоге пользователя
{'name': 'umount_userres',
'message': _("Unmouning user resources"),
'method': 'Desktop.umountUserRes(ur_mount_dirs)',
'condition': lambda dv: dv.Get('ur_mount_dirs'),
'depend': Tasks.failed()},
{'name': 'ecryptfs:umount_homedir',
'method': 'Desktop.umountUserRes(ur_home_path)',
'depend': Tasks.failed()}
]

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2008-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -14,14 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from os import path
from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable,
ActionVariable)
from calculate.lib.datavars import ActionVariable
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
setLocalTranslate('cl_desktop3', sys.modules[__name__])
class VariableAcDesktopMerge(ActionVariable):
"""
@ -30,18 +29,19 @@ class VariableAcDesktopMerge(ActionVariable):
"""
nonchroot = True
def action(self,cl_action):
def action(self, cl_action):
if cl_action == "merge":
return "on"
return "off"
class VariableAcDesktopProfile(ActionVariable):
"""
Action variable which has value "on" on user profile setup
"""
nonchroot = True
def action(self,cl_action):
def action(self, cl_action):
if cl_action in ("desktop",):
return "on"
return "off"

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2010-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2010-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -19,50 +19,60 @@ import sys
import re
from os import path
import pwd
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable, \
ReadonlyTableVariable,FieldValue
from calculate.lib.datavars import (Variable, VariableError, ReadonlyVariable,
ReadonlyTableVariable, FieldValue,
VariableInterface)
from calculate.lib.utils.common import getValueFromConfig
from calculate.lib.variables.user import VariableUrLogin
from calculate.lib.utils.files import (readLinesFile,process,isMount,
listDirectory)
from calculate.lib.utils.files import (readLinesFile, process,
listDirectory)
from calculate.desktop._cl_keys import getKey
from itertools import *
from calculate.lib.cl_template import (templateFunction,iniParser)
from calculate.lib.cl_template import templateFunction
from calculate.lib.cl_ini_parser import iniParser
import hashlib
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
_ = lambda x: x
setLocalTranslate('cl_desktop3', sys.modules[__name__])
class VariableUrJidHost(ReadonlyVariable):
"""
Jabber host for user
"""
def get(self):
userJid = self.Get("ur_jid")
if userJid:
return userJid.partition('@')[2]
return ""
class DomainInfoHelper:
class DomainInfoHelper(VariableInterface):
"""
Вспомогательный класс для определения доменный ли пользователь
"""
def getUserDataInFile(self, login, filePasswd):
return filter(lambda x: x[0]==login,
map(lambda x: x.strip().split(':'),
readLinesFile(filePasswd)))
return filter(lambda x: x[0] == login,
map(lambda x: x.strip().split(':'),
readLinesFile(filePasswd)))
def isDomainUser(self,userName):
def isDomainUser(self, userName):
if userName:
try:
passwdUserData = self.getUserDataInFile(userName, "/etc/passwd")
except:
except Exception:
return False
if passwdUserData:
passwdUserData = passwdUserData[0]
try:
cacheUserData = self.getUserDataInFile(userName,
cacheUserData = self.getUserDataInFile(
userName,
"/var/lib/calculate/calculate-client/cache/passwd")
except:
except Exception:
return False
if cacheUserData:
cacheUserData = cacheUserData[0]
@ -73,70 +83,65 @@ class DomainInfoHelper:
return False
class VariableUrDomainSet(ReadonlyVariable,DomainInfoHelper):
class VariableUrDomainSet(ReadonlyVariable, DomainInfoHelper):
"""
Flag for determining domain user or local
"""
type = "bool"
def getUserDataInFile(self, login, filePasswd):
return filter(lambda x: x[0]==login,
map(lambda x: x.strip().split(':'),
readLinesFile(filePasswd)))
def getUserDataInFile(self, login, file_passwd):
return filter(lambda x: x[0] == login,
map(lambda x: x.strip().split(':'),
readLinesFile(file_passwd)))
def get(self):
return "on" if self.isDomainUser(self.Get('ur_login')) else "off"
class VariableClDesktopXsession(ReadonlyVariable):
"""
User current X session
"""
session_list = ("kde", "gnome", "mate", "xfce", "plasma")
def get(self):
envXsessionFile = "/etc/env.d/90xsession"
xsession = os.environ.get("XSESSION",None)
desktopSession = os.environ.get("DESKTOP_SESSION",None)
xsession = os.environ.get("XSESSION", None)
desktopSession = os.environ.get("DESKTOP_SESSION", None)
if not xsession:
if os.path.exists(envXsessionFile):
xsession = \
map(lambda x:x.partition("=")[2].strip("'\""),
filter(lambda x:x.startswith("XSESSION="),
filter(lambda x:not x.startswith("#"),
open(envXsessionFile,"r"))))
if xsession:
xsession = xsession[-1]
xsession = getValueFromConfig(envXsessionFile, "XSESSION")
if xsession:
if desktopSession and \
any(x in desktopSession.lower()
for x in ("kde","xfce","gnome")):
if (desktopSession and any(x in desktopSession.lower()
for x in self.session_list)):
xsession = desktopSession
if "kde" in xsession.lower():
return "kde"
elif "gnome" in xsession.lower():
return "gnome"
elif "xfce" in xsession.lower():
return "xfce"
xsession = xsession.lower()
for session in self.session_list:
if session in xsession:
return session
else:
return xsession.lower()
return xsession
return ""
class VariableClDesktopGstData(ReadonlyVariable):
"""
GStreamer data
"""
def get(self):
# try import gst
copyargv = sys.argv
sys.argv = []
olderr = os.dup(sys.stderr.fileno())
try:
copyargv = sys.argv
sys.argv = []
olderr = os.dup(sys.stderr.fileno())
os.close(sys.stderr.fileno())
import gst
import gst.interfaces
except ImportError:
gst = None
finally:
sys.argv= copyargv
os.dup2(olderr,sys.stderr.fileno())
sys.argv = copyargv
os.dup2(olderr, sys.stderr.fileno())
if gst is None:
return {}
@ -149,48 +154,55 @@ class VariableClDesktopGstData(ReadonlyVariable):
outdata['device_name'] = alsamixer.get_property("device-name")
outdata['long_name'] = alsamixer.get_factory().get_longname()
outdata['internal_name'] = filter(str.isalnum,
"%s (%s)"%(outdata['device_name'],
outdata['long_name']))
"%s (%s)" % (
outdata['device_name'],
outdata['long_name']))
outdata['channels'] = []
for t in alsamixer.list_tracks():
if t.flags & gst.interfaces.MIXER_TRACK_OUTPUT:
if t.flags & gst.interfaces.MIXER_TRACK_MASTER or \
any(x in t.label
for x in ("Wave","Front","LFE","Center",
"Head","Side","Speaker",
"Surround","PCM")):
any(x in t.label
for x in ("Wave", "Front", "LFE", "Center",
"Head", "Side", "Speaker",
"Surround", "PCM")):
outdata['channels'].append(t.label)
if t.flags & gst.interfaces.MIXER_TRACK_MASTER:
outdata['master_channel'] = t.label
except:
except Exception:
pass
return outdata
class VariableClDesktopGstCard(ReadonlyVariable):
"""
Internal card name for xfce mixer
"""
def get(self):
return self.Get('cl_desktop_gst_data').get('internal_name','')
return self.Get('cl_desktop_gst_data').get('internal_name', '')
class VariableClDesktopGstMasterchannel(ReadonlyVariable):
"""
Master track name
"""
def get(self):
return self.Get('cl_desktop_gst_data').get('master_channel','')
return self.Get('cl_desktop_gst_data').get('master_channel', '')
class VariableClDesktopXfceMixer(ReadonlyVariable):
"""
List of channel for xfce-perchannel mixer
"""
def get(self):
return "\n".join(
map(lambda x:' <value type="string" value="%s" />'%x,
self.Get('cl_desktop_gst_data').get('channels',[])))
map(lambda x: ' <value type="string" value="%s" />' % x,
self.Get('cl_desktop_gst_data').get('channels', [])))
class VariableClDesktopOnlineData(ReadonlyTableVariable,DomainInfoHelper):
class VariableClDesktopOnlineData(ReadonlyTableVariable, DomainInfoHelper):
"""
Information about online users
"""
@ -202,52 +214,53 @@ class VariableClDesktopOnlineData(ReadonlyTableVariable,DomainInfoHelper):
reDisplay = re.compile(r"^\(?:(\d+\.?\d*)")
def _getDisplay(self,*args):
def _getDisplay(self, *args):
"""
Get DISPLAY from args
"""
for arg in map(self.reDisplay.search,args):
for arg in map(self.reDisplay.search, args):
if arg:
return arg.group(1)
return ""
def get_user_uid(self,username):
def get_user_uid(self, username):
try:
return str(pwd.getpwnam(username).pw_uid)
except:
except Exception:
return ""
def get(self,hr=False):
xSession = 0
foundTwoSession = False
def get(self, hr=False):
# TODO: need to KISS rewrite
resWho = process("who")
xData = [[]]
if resWho.success():
listProcessing = lambda x: (x[0], x[1], x[-1]) \
if len(x)>=5 else []
if len(x) >= 5 else []
xData = groupby(
sorted(
filter(lambda x: x[0]!="root",
map(lambda x: (x[0],self._getDisplay(x[1],x[2])),
filter(lambda x: x and\
(x[2].startswith("(:") or \
x[1].startswith(":")),
map(lambda x: listProcessing(\
filter(lambda y: y, x.split())),
resWho)))),
key=lambda x:x[0]),
lambda x:x[0])
xData = map(lambda x:(x[0][0],x[0][1],
self.get_user_uid(x[0][0]),
"on" if self.isDomainUser(x[0][0]) else "off",
len(x)),
map(lambda x:list(x[1]),
xData))
sorted(
filter(lambda x: x[0] != "root",
map(lambda x: (x[0], self._getDisplay(x[1], x[2])),
filter(lambda x: x and \
(x[2].startswith("(:") or
x[1].startswith(":")),
map(lambda x: listProcessing(
filter(lambda y: y, x.split())),
resWho)))),
key=lambda x: x[0]),
lambda x: x[0])
xData = map(lambda x: (x[0][0], x[0][1],
self.get_user_uid(x[0][0]),
"on" if self.isDomainUser(
x[0][0]) else "off",
len(x)),
map(lambda x: list(x[1]),
xData))
return xData
setValue = Variable.setValue
class VariableClDesktopOnlineUser(FieldValue,ReadonlyVariable):
class VariableClDesktopOnlineUser(FieldValue, ReadonlyVariable):
"""
Логин пользователя
"""
@ -255,7 +268,8 @@ class VariableClDesktopOnlineUser(FieldValue,ReadonlyVariable):
source_variable = "cl_desktop_online_data"
column = 0
class VariableClDesktopOnlineDisplay(FieldValue,ReadonlyVariable):
class VariableClDesktopOnlineDisplay(FieldValue, ReadonlyVariable):
"""
Display пользователя
"""
@ -263,7 +277,8 @@ class VariableClDesktopOnlineDisplay(FieldValue,ReadonlyVariable):
source_variable = "cl_desktop_online_data"
column = 1
class VariableClDesktopOnlineUid(FieldValue,ReadonlyVariable):
class VariableClDesktopOnlineUid(FieldValue, ReadonlyVariable):
"""
UID пользователя
"""
@ -271,7 +286,8 @@ class VariableClDesktopOnlineUid(FieldValue,ReadonlyVariable):
source_variable = "cl_desktop_online_data"
column = 2
class VariableClDesktopOnlineDomainSet(FieldValue,ReadonlyVariable):
class VariableClDesktopOnlineDomainSet(FieldValue, ReadonlyVariable):
"""
Является ли пользователь доменным
"""
@ -279,7 +295,8 @@ class VariableClDesktopOnlineDomainSet(FieldValue,ReadonlyVariable):
source_variable = "cl_desktop_online_data"
column = 3
class VariableClDesktopOnlineCount(FieldValue,ReadonlyVariable):
class VariableClDesktopOnlineCount(FieldValue, ReadonlyVariable):
"""
Количество сеансов пользователя
"""
@ -287,6 +304,7 @@ class VariableClDesktopOnlineCount(FieldValue,ReadonlyVariable):
source_variable = "cl_desktop_online_data"
column = 4
class VariableClDesktopLogin(VariableUrLogin):
"""
User Login
@ -299,20 +317,21 @@ class VariableClDesktopLogin(VariableUrLogin):
else:
return VariableUrLogin.choice(self)
def check(self,value):
def check(self, value):
"""Does user exist"""
if not value in self.choice() and self.Get('cl_action') == 'logout':
if value not in self.choice() and self.Get('cl_action') == 'logout':
raise VariableError(_("No X session user found"))
if value == "":
raise VariableError(_("Please specify the user name"))
try:
pwd.getpwnam(value).pw_gid
except:
raise VariableError(_("User %s does not exist")%value)
except Exception:
raise VariableError(_("User %s does not exist") % value)
def get(self):
return ""
class VariableUrMountDirs(ReadonlyVariable):
"""
Примонтированные директории в профиле пользователя
@ -324,26 +343,30 @@ class VariableUrMountDirs(ReadonlyVariable):
if not homeDir:
return []
dirStart, dirEnd = path.split(homeDir)
mountProfileDir = path.join(dirStart, ".%s" %dirEnd)
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd)
directories = filter(lambda x:x != homeDir,
filter(lambda x: (x.startswith(homeDir) or
x.startswith(mountProfileDir) or
x.startswith(mountRemoteProfileDir)),
map(lambda x: x.split(" ")[1],
readLinesFile('/proc/mounts'))))
#if isMount(homeDir):
mountProfileDir = path.join(dirStart, ".%s" % dirEnd)
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" % dirEnd)
directories = filter(lambda x: x != homeDir,
filter(lambda x: (x.startswith(homeDir) or
x.startswith(mountProfileDir) or
x.startswith(
mountRemoteProfileDir)),
map(lambda x: x.split(" ")[1],
readLinesFile('/proc/mounts'))))
# if isMount(homeDir):
# directories.append(homeDir)
return sorted(directories,reverse=True)
return sorted(directories, reverse=True)
class VariableUrPassword(ReadonlyVariable):
"""
Пароль пользователя, получаемый из ключей ядра
"""
def get(self):
return getKey(self.Get('ur_login')) or ""
class VariableClDesktopUpdateProfileSet(Variable):
"""
Нужно ли выполнять обновление профиля пользователя на основании
@ -353,19 +376,20 @@ class VariableClDesktopUpdateProfileSet(Variable):
def get(self):
lastTimestamp = templateFunction.getLastElog()
iniEnv = path.join(self.Get('ur_home_path'),'.calculate/ini.env')
iniEnv = path.join(self.Get('ur_home_path'), '.calculate/ini.env')
userIni = iniParser(iniEnv)
userTimestamp = userIni.getVar('main','elog')
userTimestamp = userIni.getVar('main', 'elog')
if userTimestamp:
userTimestamp = userTimestamp.encode('utf-8')
profileSetup = userIni.getVar('main','profile_setup')
profileSetup = userIni.getVar('main', 'profile_setup')
login_setup = profileSetup == 'on'
if (self.Get('ur_domain_set') == 'on' or login_setup or
not path.exists(iniEnv) or userTimestamp != lastTimestamp):
not path.exists(iniEnv) or userTimestamp != lastTimestamp):
return 'on'
else:
return 'off'
class VariableClDesktopForceSetupSet(Variable):
"""
Принудительно выполнить обновление пользовательского профиля
@ -379,37 +403,43 @@ class VariableClDesktopForceSetupSet(Variable):
self.label = _("Force configuration")
self.help = _("force configuration")
class VariableClDesktopFacePath(Variable):
"""Путь к стандартным иконкам пользователей"""
value = "/usr/share/pixmaps/faces"
class VariableClDesktopFaceList(Variable):
"""Список доступных иконок по умолчанию для пользователей"""
type = "list"
def get(self):
return sorted(
filter(lambda x:x.endswith('.png'),
listDirectory(self.Get('cl_desktop_face_path'))))
filter(lambda x: x.endswith('.png'),
listDirectory(self.Get('cl_desktop_face_path'))))
class VariableClDesktopHashFace(Variable):
"""Номер иконки пользователя
Номер вычисляется по контрольной сумму md5 логина пользователя
"""
def get(self):
login = self.Get('ur_login')
icon_list = self.Get('cl_desktop_face_list')
if icon_list:
return path.join(self.Get('cl_desktop_face_path'),
icon_list[sum(map(lambda x:ord(x),
hashlib.md5(login).digest()))%len(icon_list)])
icon_list[sum(map(lambda x: ord(x),
hashlib.md5(
login).digest())) % len(
icon_list)])
else:
return ""
class VariableClDesktopFastloginPath(ReadonlyVariable):
"""
Путь до каталога в котором указаны пользователи быстрого входа в сеанс
"""
value = "/var/lib/calculate/calculate-desktop/fastlogin"

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-2015 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -13,16 +13,18 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys, time, os
import sys
from calculate.lib.datavars import VariableError,DataVarsError,DataVars
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.core.server.func import WsdlBase
from desktop import DesktopError
from utils.cl_desktop import ClDesktopLogoutAction,ClDesktopAction
from utils.cl_desktop import ClDesktopLogoutAction, ClDesktopAction
import desktop
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_desktop3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
@ -32,69 +34,70 @@ class Wsdl(WsdlBase):
# вывести пользователя из сеанса
#
{
# идентификатор метода
'method_name':"desktop_logout",
# категория метода
'category':__('Desktop'),
# заголовок метода
'title':__("User Logout"),
# иконка для графической консоли
'image':'system-log-out',
# метод присутствует в графической консоли
'gui':True,
# консольная команда
'command':'cl-desktop-logout',
# права для запуска метода
'rights':['userconfigure'],
# объект содержащий модули для действия
'logic':{'Desktop':desktop.Desktop},
# описание действия
'action':ClDesktopLogoutAction,
# объект переменных
'datavars':"desktop",
'native_error':(VariableError,DataVarsError,
DesktopError),
# значения по умолчанию для переменных этого метода
'setvars':{'cl_action!':'logout'},
# описание груп (список лямбда функций)
'groups':[
lambda group:group(_("User logout"),
normal=('cl_desktop_login',),
next_label=_("Execute"))]},
# идентификатор метода
'method_name': "desktop_logout",
# категория метода
'category': __('Desktop'),
# заголовок метода
'title': __("User Logout"),
# иконка для графической консоли
'image': 'system-log-out',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-desktop-logout',
# права для запуска метода
'rights': ['userconfigure'],
# объект содержащий модули для действия
'logic': {'Desktop': desktop.Desktop},
# описание действия
'action': ClDesktopLogoutAction,
# объект переменных
'datavars': "desktop",
'native_error': (VariableError, DataVarsError,
DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'logout'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("User logout"),
normal=('cl_desktop_login',),
next_label=_("Execute"))]},
#
# настроить пользовательский сеанс
#
{
# идентификатор метода
'method_name':"desktop",
# категория метода
'category':__('Desktop'),
# заголовок метода
'title':__("User Account Configuration"),
# иконка для графической консоли
'image':'user-desktop,preferences-desktop',
# метод присутствует в графической консоли
'gui':True,
# консольная команда
'command':'cl-desktop',
# права для запуска метода
'rights':['userconfigure'],
# объект содержащий модули для действия
'logic':{'Desktop':desktop.Desktop},
# описание действия
'action':ClDesktopAction,
# объект переменных
'datavars':"desktop",
'native_error':(VariableError,DataVarsError,
DesktopError),
# значения по умолчанию для переменных этого метода
'setvars':{'cl_action!':'desktop',
'cl_protect_use_set!':'off'},
# описание груп (список лямбда функций)
'groups':[
lambda group:group(_("User account configuration"),
normal=('ur_login',),
expert=('cl_desktop_force_setup_set','cl_verbose_set',
'cl_templates_locate'),
next_label=_("Execute"))]},
]
# идентификатор метода
'method_name': "desktop",
# категория метода
'category': __('Desktop'),
# заголовок метода
'title': __("User Account Configuration"),
# иконка для графической консоли
'image': 'user-desktop,preferences-desktop',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-desktop',
# права для запуска метода
'rights': ['userconfigure'],
# объект содержащий модули для действия
'logic': {'Desktop': desktop.Desktop},
# описание действия
'action': ClDesktopAction,
# объект переменных
'datavars': "desktop",
'native_error': (VariableError, DataVarsError,
DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'desktop',
'cl_protect_use_set!': 'off'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("User account configuration"),
normal=('ur_login',),
expert=('cl_desktop_force_setup_set',
'cl_verbose_set',
'cl_templates_locate'),
next_label=_("Execute"))]},
]

Loading…
Cancel
Save