Solutions: Improvements of class PyAD
Settings.py
Now it is time to introduce some global, i.e. program wide variables:
1 2 3 |
class Settings: dnSchool = "dc=trainingX, dc=net" # Distinguished of domaine dnStudents = "ou=Students, ou=SchoolUsers, " + dnSchool # Distinguished Name of OU Students |
The Settings class here is not instantiated (no object created). These so-called static properties can easily be accessed via [class name].[property name] (see below)
(A static variable exists only once per class and is common to all objects of this class. If the value of a static variable in an object is changed, the value in all other instances of the class is also changed.)
PyAD.py
Beside the unchanged abstract class AbstractLDAP the improved code of class PyAD is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
from abc import ABC, abstractmethod # import Abstract Base Classes (ABCs) class AbstractLDAP(ABC): def __init__(self, dnStudents): self._dnStudents = dnStudents super().__init__() @abstractmethod def createStudent(self, username, nameSchoolClass): pass @abstractmethod def deleteStudent(self, username, nameSchoolClass): pass @abstractmethod def createSchoolClass(self, nameSchoolClass): pass @abstractmethod def deleteSchoolClass(self, nameSchoolClass): pass from pyad import * from Settings import Settings class PyAD(AbstractLDAP): def createStudent(self, username, surname, firstname, password, dateOfBirth, nameSchoolClass): query = adquery.ADQuery() cnUnique = False numChar = 0 while(cnUnique == False): query.execute_query(attributes = ["cn"], # query: does cn already exist where_clause=("cn = '" + username + "'"), base_dn = Settings.dnSchool) if query.get_row_count() > 0: # yes: add character numChar = numChar + 1 if(numChar <= len(firstname)): # if the character set of the first name is large enough username = surname + firstname[:numChar] # add number of characters from beginning of first ame else: # if the character set of the first name is used up username = surname + firstname + (numChar - len(firstname)) * 'x' # added number of 'x' else: # cn is unique => create user cnUnique = True ouSchoolClass = pyad.adcontainer.ADContainer("ou="+nameSchoolClass+", "+self._dnStudents, adsi_ldap_com_object=None, options={}) aduser.ADUser.create(username , ouSchoolClass , password=password , upn_suffix=None , enable=True , optional_attributes={"sn":surname , "givenName":firstname , "employeeID":dateOfBirth # using existing employeeId attribute is easier than extending AD scheme , "description":"Student" , "pwdLastSet":0}) # password must be changed on first login return username # return possibly modified username def deleteStudent(self, surname, firstname, dateOfBirth, nameSchoolClass): # print("delete ", surname, firstname, dateOfBirth, nameSchoolClass) dnSchoolClass = "ou="+nameSchoolClass + ", " + self._dnStudents query = adquery.ADQuery() query.execute_query(attributes = ["cn"], where_clause=("sn = '" + surname + "' and givenName = '" + firstname + "' and employeeID = '" + dateOfBirth + "'"), base_dn = dnSchoolClass) if query.get_row_count() >= 1: # if student exists => delete it ouSchoolClass = pyad.adcontainer.ADContainer(dnSchoolClass, adsi_ldap_com_object=None, options={}) for row in query.get_results(): ouSchoolClass.from_cn(row["cn"]).delete() def createSchoolClass(self, nameSchoolClass): query = adquery.ADQuery() query.execute_query(attributes = ["distinguishedName"], where_clause=("ou = '" +nameSchoolClass + "'"), base_dn = self._dnStudents) if query.get_row_count() == 0: # if school class not yet exists => create ouStudents = pyad.adcontainer.ADContainer(self._dnStudents, adsi_ldap_com_object=None, options={}) ouStudents.create_container(nameSchoolClass) def deleteSchoolClass(self, nameSchoolClass): dnSchoolClass = "ou="+nameSchoolClass+", "+ self._dnStudents query = adquery.ADQuery() query.execute_query(attributes = ["distinguishedName"], where_clause=("ou = '" +nameSchoolClass + "'"), base_dn = self._dnStudents) if query.get_row_count() == 1: # if school class exists query = adquery.ADQuery() query.execute_query(attributes = ["sn", "givenName", "employeeID"], # employeeID holds date of birth, where_clause=("cn = '*'"), base_dn = dnSchoolClass) if query.get_row_count() > 0: # if school class not empty for row in query.get_results(): # delete students self.deleteStudent(row["sn"], row["givenName"], row["employeeID"], nameSchoolClass) ouSchoolClass = pyad.adcontainer.ADContainer(dnSchoolClass, adsi_ldap_com_object=None, options={}) ouSchoolClass.delete() # delete school class |
The method createStudent() returns the possibly modified username so that it can be updated later in the class Student.
The student to be deleted is uniquely identified by the parameters surname, firstname, dateOfBirth and nameSchoolClass of the method deleteStudent.
testPyAD.py
The classes are used as follows:
1 2 3 4 5 6 7 8 |
from Settings import Settings from Ldap import PyAD ldap = PyAD(Settings.dnStudents) ldap.createSchoolClass("school_class1") ldap.createStudent("Miller", "Miller", "Sam", "SM11.11.2000", "11.11.2000", "school_class1") # ldap.deleteSchoolClass("school_class1") |