├── .gitignore ├── .project ├── .pydevproject ├── .settings ├── org.eclipse.ltk.core.refactoring.prefs └── org.springframework.ide.eclipse.xml.namespaces.prefs ├── AboutDlg.xrc ├── AdmDialogs.py ├── Admin4.icns ├── Admin4.ico ├── Admin4.png ├── Admin4Small.png ├── CHANGELOG ├── Critical.png ├── Debug.png ├── Error.png ├── FindPanel.xrc ├── HOW-TO.md ├── HintDlg.xrc ├── Info.png ├── KNOWN-BUGS ├── LICENSE.TXT ├── LogPanel.xrc ├── LoggingDialog.py ├── LoggingDialog.xrc ├── PagedPropertyDlg.xrc ├── PasswordDlg.xrc ├── Preferences.xrc ├── PreferencesDlg.xrc ├── README.V2 ├── README.md ├── TODO.md ├── Update.py ├── UpdateDlg.xrc ├── Validator.py ├── adm.py ├── admin4.py ├── close.png ├── close_inactive.png ├── config.py ├── connect.png ├── controlcontainer.py ├── createBundle.py ├── ctl_adm.py ├── delete.png ├── detach.png ├── docker ├── Dockerfile ├── admin4 ├── build-container.sh ├── debug-container.sh ├── push-container.sh └── run-container.sh ├── edit.png ├── edit_find.png ├── find.png ├── folder.png ├── frame.py ├── logger.py ├── main.py ├── modBind ├── CatalogHostRecord.xrc ├── CatalogMemberRecord.xrc ├── CatalogZone.png ├── HOWTO ├── HostRecord.xrc ├── MultiValRecords.xrc ├── RevZone.png ├── Server.png ├── Server.py ├── Server.xrc ├── SingleValRecord.xrc ├── SingleValRecords.xrc ├── Zone.png ├── Zone.py ├── Zone.xrc ├── __init__.py ├── _dns.py └── _requires.py ├── modImap ├── Mailbox.png ├── Mailbox.py ├── Mailbox.xrc ├── MailboxAcl.xrc ├── MailboxNoselect.png ├── Server.png ├── Server.py ├── Server.xrc ├── User.png ├── __init__.py ├── _imap.py ├── _requires.py └── imap_utf7.py ├── modLdap ├── Computer.png ├── Contact.xrc ├── Entry.png ├── Entry.py ├── GenericEntry.py ├── GenericEntry.xrc ├── Group.png ├── Group.py ├── Group.xrc ├── Groups.xrc ├── OrgUnit.png ├── Personal.xrc ├── Posix.py ├── PosixUser.png ├── Preferences.xrc ├── SamUser.png ├── Samba.py ├── SambaAccount.xrc ├── SambaDomain.png ├── SambaDomain.xrc ├── SambaGroupMapping.xrc ├── Server.png ├── Server.py ├── Server.xrc ├── ServerConfig.xrc ├── ShadowAccount.xrc ├── SpecificEntry.py ├── User.png ├── UserAccount.xrc ├── __init__.py ├── _ldap.py ├── _requires.py ├── attribEmpty.png ├── attribMay.png ├── attribMust.png ├── attribRDN.png ├── hints │ └── instrument.html └── objectClass.png ├── modPg ├── ColumnPanel.xrc ├── ConnectDlg.xrc ├── ConnectionPage.xrc ├── DEBUG.png ├── DataTool.py ├── Database-conn.png ├── Database-noconn.png ├── Database.png ├── Database.py ├── ERROR.png ├── FATAL.png ├── Favourite.py ├── Favourites.png ├── FilterPanel.xrc ├── Function.png ├── Function.py ├── LOG.png ├── LoggingPage.xrc ├── LoglineDlg.xrc ├── MatView.png ├── Partition.png ├── PartitionedTable.png ├── Preferences.xrc ├── PrivilegePanel.xrc ├── QueryTool.py ├── Role.png ├── Role.py ├── Roles.png ├── Schema.png ├── Schema.py ├── Sequence.png ├── Sequence.py ├── Sequence.xrc ├── Server.ico ├── Server.py ├── Server.xrc ├── ServerPages.py ├── ServerSetting.xrc ├── SettingsPage.xrc ├── SqlData.ico ├── SqlPanel.xrc ├── SqlQuery.ico ├── Table.png ├── Table.py ├── View.png ├── View.py ├── __init__.py ├── _explain.py ├── _objects.py ├── _pgsql.py ├── _requires.py ├── _snippet.py ├── _sqledit.py ├── _sqlgrid.py ├── admin.png ├── check.png ├── clip_copy.png ├── clip_cut.png ├── clip_paste.png ├── column.png ├── data_refresh.png ├── data_save.png ├── delete.png ├── edit_clear.png ├── edit_find.png ├── edit_redo.png ├── edit_undo.png ├── ex_aggregate.png ├── ex_append.png ├── ex_bmp_heap.png ├── ex_bmp_index.png ├── ex_group.png ├── ex_hash.png ├── ex_index_scan.png ├── ex_join.png ├── ex_limit.png ├── ex_materialize.png ├── ex_merge.png ├── ex_nested.png ├── ex_result.png ├── ex_scan.png ├── ex_seek.png ├── ex_setop.png ├── ex_sort.png ├── ex_subplan.png ├── ex_tid_scan.png ├── ex_unique.png ├── ex_unknown.png ├── fav.png ├── file_open.png ├── file_save.png ├── filter.png ├── foreignkey.png ├── group.png ├── hints │ └── instrument.html ├── index.png ├── key.png ├── kwlist.h ├── pg.png ├── primarykey.png ├── query_cancel.png ├── query_execfile.png ├── query_execute.png ├── query_explain.png ├── setting.png ├── settingChanged.png ├── settingInternal.png ├── snippet.png ├── snippet_add.png ├── snippet_replace.png ├── snippets.png ├── statistics.png └── user.png ├── new.png ├── node.py ├── notebook.py ├── page.py ├── property.png ├── refresh.png ├── requirements-mac.txt ├── tree.py ├── version.py ├── wh.py ├── wxWidgets.ico ├── xmlhelp.py ├── xmlres.py └── xrced ├── XRCed_16.png ├── XRCed_32.png ├── encode_bitmaps.py ├── globals.py ├── images.py ├── license.txt ├── panel.py ├── params.py ├── tools.py ├── tree.py ├── undo.py ├── xrced.ico ├── xrced.py ├── xrced.xrc └── xxx.py /.gitignore: -------------------------------------------------------------------------------- 1 | __version.py 2 | .build/ 3 | .DS_Store 4 | modXa 5 | 6 | # Nano 7 | *.swp 8 | 9 | # Byte-compiled / optimized / DLL files 10 | __pycache__/ 11 | *.py[cod] 12 | 13 | # C extensions 14 | *.so 15 | 16 | # Distribution / packaging 17 | .Python 18 | env/ 19 | bin/ 20 | build/ 21 | develop-eggs/ 22 | dist/ 23 | eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | 48 | # Mr Developer 49 | .mr.developer.cfg 50 | 51 | # Rope 52 | .ropeproject 53 | 54 | # Django stuff: 55 | *.log 56 | *.pot 57 | 58 | # Sphinx documentation 59 | docs/_build/ 60 | 61 | /release 62 | /_update 63 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Admin4 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | 19 | 1475337436558 20 | 21 | 22 22 | 23 | org.eclipse.ui.ide.multiFilter 24 | 1.0-name-matches-false-false-*.png 25 | 26 | 27 | 28 | 1475337436562 29 | 30 | 22 31 | 32 | org.eclipse.ui.ide.multiFilter 33 | 1.0-name-matches-false-false-*.ico 34 | 35 | 36 | 37 | 1475337436564 38 | 39 | 22 40 | 41 | org.eclipse.ui.ide.multiFilter 42 | 1.0-name-matches-false-false-*.xrc 43 | 44 | 45 | 46 | 1475337436566 47 | 48 | 10 49 | 50 | org.eclipse.ui.ide.multiFilter 51 | 1.0-name-matches-false-false-release 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Python3.13 5 | 6 | python interpreter 7 | 8 | 9 | -------------------------------------------------------------------------------- /.settings/org.eclipse.ltk.core.refactoring.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false 3 | -------------------------------------------------------------------------------- /.settings/org.springframework.ide.eclipse.xml.namespaces.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.springframework.ide.eclipse.xml.namespaces.default.version.check.classpath=true 3 | org.springframework.ide.eclipse.xml.namespaces.enable.project.preferences=false 4 | org.springframework.ide.eclipse.xml.namespaces.loadNamespaceHandlerFromClasspath=true 5 | org.springframework.ide.eclipse.xml.namespaces.use.https.for.new.namespace.locations=false 6 | -------------------------------------------------------------------------------- /AboutDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | About 5 | 1 6 | 7 | 8 | 9 | 10 | Admin4.png 11 | 12 | 13 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW|wxALIGN_CENTRE_VERTICAL 14 | 10 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | wxVERTICAL 23 | 24 | 25 | 26 | 27 | wxALIGN_CENTRE|wxTOP 28 | 20 29 | 30 | 31 | 32 | 33 | 34 | wxALIGN_CENTRE|wxTOP 35 | 10 36 | 1 37 | 38 | 39 | 40 | 41 | 42 | 43 | wxALIGN_CENTRE|wxTOP 44 | 2 45 | 1 46 | 47 | 48 | 49 | 50 | 51 | 52 | wxALIGN_CENTRE|wxTOP 53 | 20 54 | 1 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 250,-1d 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | wxTOP|wxBOTTOM|wxRIGHT|wxGROW 79 | 10 80 | 81 | 2 82 | 1 83 | 0 84 | 1 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Admin4.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Admin4.icns -------------------------------------------------------------------------------- /Admin4.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Admin4.ico -------------------------------------------------------------------------------- /Admin4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Admin4.png -------------------------------------------------------------------------------- /Admin4Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Admin4Small.png -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2 | 3 | V2 End Of Life 4 | 5 | modBind 0.98.8: 6 | - Fix for Bind9.9 7 | Core: 8 | - Fix splitValUnit() as reported by Catalin Mocanu 9 | 10 | modBind 0.98.7: 11 | CAA support (with modpython 1.15) 12 | BIND9.10 support 13 | 14 | modPg 0.5.10: 15 | Datatool sort DESC 16 | Table SQL 17 | 18 | modPg 0.5.9: 19 | roles 9.5+ 20 | 21 | modImap 0.5.7: 22 | fix squat 23 | 24 | Changes in 2.2.2: 25 | Core: 26 | - skip verify SSL certificates when downloading updates 27 | 28 | Changes in 2.2.1: 29 | Core: 30 | - ver/rev/mods in update query url 31 | - restart application after update undone; doesn't work 32 | - fix for manual module update 33 | - Fix DisplayDialog to use Frame or Dialog as parentWin 34 | - self.dialog.node.GetCursor().ExecuteDictList 35 | 36 | modImap 0.5.6: 37 | - ACL fixes 38 | modImap 0.5.5: 39 | - recursion fixes 40 | modImap 0.5.4: 41 | - set/del Acl recursive 42 | 43 | modImap 0.5.3: 44 | - fix rights override when deleting for older cyrus 45 | - utf-8 workaround in annotations 46 | 47 | modImap 0.5.2: 48 | - setacl 49 | - acl change fix 50 | - acl who name checking 51 | - quota on Noselect mailboxes 52 | 53 | modBind 0.98.6: 54 | - Fix bool MayHaveChildren() 55 | 56 | modLdap 0.95.10: 57 | - Fix bool MayHaveChildren() 58 | - Squat flag support 59 | 60 | modPg 0.5.8: 61 | - fix connectionPool leak in DataTool 62 | - quoteIdent fixes 63 | - pg_stat_activity fixes 64 | - basic Column support 65 | modPg 0.5.7: 66 | - fix instrumentation if postgresql.conf not in data_directory (debian...) 67 | 68 | 69 | Changes in 2.2.0 70 | Core: 71 | - prepare to use wx 3.0.1.1 on Windows 72 | - fix png iCCS msgbox 73 | - fix shlexSplit with None Argument 74 | - fix node Delete handling in frame 75 | - check node MayHaveChildren in tree.Refresh() 76 | - remove module load restriction from config 77 | - floatToSize() with resolution 78 | - imaplib added (lib 2.1.9) 79 | - Version() work 80 | 81 | modLdap 0.95.9: 82 | - ldap group member candidate fix 83 | 84 | modPg 0.5.6: 85 | - sslmode in connectString was missing 86 | 87 | modImap 0.5.0: 88 | - new 89 | 90 | 91 | Changes in 2.1.9 92 | Core: 93 | - Fix binary download in online update 94 | - removeSmartQuote, quoteIfNeeded 95 | 96 | modPg 0.5.5: 97 | - optimize Favourites speed 98 | 99 | modBind 0.98.5: 100 | - Allow values with spaces as single string using quotes 101 | 102 | modLdap 0.95.8: 103 | - fix Samba code 104 | 105 | 106 | Changes in 2.1.8 107 | Core: 108 | - shlexSplit 109 | 110 | modPg 0.5.4: 111 | - minimal Sequence support 112 | - GrantCommentSql 113 | - Favourites fix 114 | 115 | modLdap 0.95.7: 116 | - fix crash when a duplicated attribute is deleted 117 | - smoother automatic RID generation 118 | - SambaAccount includes PosixAccount 119 | - fix SambaGroup 120 | 121 | 122 | 123 | Changes in 2.1.7 124 | Core: 125 | - Fix in Update Download SHA calculation 126 | 127 | modLdap 0.95.6: 128 | - fixes for uid/gid/rid generation 129 | - User with sambaAcctFlag [U] 130 | 131 | 132 | 133 | Changes in 2.1.6 134 | Core: 135 | - F5 refresh 136 | - fix in default FindObject when notFound 137 | - periodic automatic update 138 | 139 | modPg 0.5.3: 140 | - use SqlEditor in DataTool filter 141 | - ServerLog 142 | - Config page: better visualization of found entry, supports 8.1+ 143 | 144 | modLdap 0.95.5: 145 | - fix SSHA password unicode error 146 | 147 | modBind 0.98.4: 148 | - remember position when editing zone record 149 | 150 | 151 | 152 | Changes in 2.1.5 153 | Core: 154 | - Shift key while starting suppresses auto-connect 155 | - two-level online update (major/minor) 156 | - FindObject 157 | 158 | modLdap 0.95.4: 159 | - FindObject in database 160 | 161 | modPg 0.5.2: 162 | - force client_encoding to utf8 163 | - FindObject in database 164 | 165 | modPg 0.5.1: 166 | - fix empty preset preventing Data Tool to come up 167 | 168 | 169 | 170 | Changes in 2.1.4 171 | Core: 172 | - Online update 173 | - fix in Frame.OnCall 174 | - support NotebookPage.availableOn 175 | - remember nodePath 176 | - refactoring of Menu() 177 | 178 | modLdap 0.95.3: 179 | - fix connect to non-instrumented Active Directory 180 | - fix multi-value octet attribs 181 | 182 | modBind 0.98.3: 183 | - check status connection 184 | 185 | modPg 0.5.0: 186 | - pgConnectionPool/pgCursor 187 | - improved QueryTool: 188 | - SQL Snippets 189 | - menu fix 190 | - QueryTool file functions 191 | - syntax highlighting 192 | - error marking 193 | - Data Tool including presets 194 | 195 | 196 | 197 | Changes in 2.1.3 198 | Core: 199 | - Core and Module update procedure 200 | - AskPassword remembers password 201 | 202 | modLdap 0.95.2: 203 | - updatable 204 | 205 | modBind 0.98.2: 206 | - updatable 207 | 208 | 209 | 210 | Changes in 2.1.2 (2014-04-30) 211 | Core: 212 | - centralized AskPassword 213 | - uint Validator length check fix 214 | 215 | modLdap 0.95.1: 216 | - cleanup ConnectionException 217 | - fix changing server properties 218 | 219 | modBind 0.98.1: 220 | - fix manual RemoveZone 221 | - add manual AddRevZone 222 | -------------------------------------------------------------------------------- /Critical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Critical.png -------------------------------------------------------------------------------- /Debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Debug.png -------------------------------------------------------------------------------- /Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Error.png -------------------------------------------------------------------------------- /FindPanel.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | wxBOTTOM|wxRIGHT|wxEXPAND|wxGROW 10 | 5 11 | 12 | 13 | 14 | wxHORIZONTAL 15 | 16 | 17 | close_inactive.png 18 | 19 | 20 | wxRIGHT|wxALIGN_CENTRE_VERTICAL 21 | 5 22 | 23 | 24 | 25 | 80,-1d 26 | 27 | 28 | 29 | wxALIGN_CENTRE_VERTICAL 30 | 31 | 32 | 33 | find.png 34 | 35 | wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL 36 | 5 37 | 38 | 39 | wxBOTTOM|wxLEFT|wxEXPAND 40 | 5 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /HOW-TO.md: -------------------------------------------------------------------------------- 1 | # Icons 2 | http://www.iconarchive.com/show/dragon-soft-icons-by-artua/Toolbox-icon.html 3 | http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org.html 4 | 5 | # Mac OSX 10.14: 6 | 7 | pip3 install dnspython 8 | pip3 install python-ldap 9 | pip3 install psycopg2-binary 10 | pip3 install wxPython 11 | 12 | 13 | ## for createBundle: 14 | pip3 install gitpython 15 | pip3 install py2app 16 | 17 | Eclipse/PyDev 18 | - tabsize 2 19 | - ignore name evt 20 | - ignore builtin names 21 | 22 | -------------------------------------------------------------------------------- /HintDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hint 5 | 200,200d 6 | 7 | 8 | wxVERTICAL 9 | 10 | 11 | 12 | wxLEFT|wxRIGHT|wxEXPAND 13 | 10 14 | 150,100d 15 | 16 | 17 | 18 | wxHORIZONTAL 19 | 20 | 21 | 22 | 1 23 | 24 | wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 100,180d 33 | 1 34 | 35 | wxALIGN_RIGHT 36 | 37 | 38 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 39 | 10 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/Info.png -------------------------------------------------------------------------------- /KNOWN-BUGS: -------------------------------------------------------------------------------- 1 | wxPython < 4.1.2: 2 | GridStringTable misses base class https://github.com/wxWidgets/wxWidgets/pull/22258 3 | -------------------------------------------------------------------------------- /LogPanel.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | wxEXPAND|wxGROW 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | wxALIGN_CENTRE_VERTICAL 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | wxALIGN_CENTRE_VERTICAL 26 | 50,-1d 27 | 28 | 29 | 30 | 31 | 32 | wxALIGN_CENTRE_VERTICAL 33 | 34 | 35 | wxEXPAND|wxGROW 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | wxRIGHT|wxALIGN_CENTRE_VERTICAL 47 | 48 | 6 49 | 10 50 | 2 51 | 52 | wxTOP|wxBOTTOM|wxALL|wxEXPAND|wxGROW 53 | 10 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /PagedPropertyDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Paged Property 5 | 6 | 7 | wxVERTICAL 8 | 9 | 10 | 11 | wxEXPAND 12 | 13 | 14 | 15 | wxHORIZONTAL 16 | 17 | 18 | 19 | 20 | 21 | 22 | 40,145d 23 | 45,15d 24 | 25 | wxBOTTOM|wxRIGHT 26 | 5d 27 | 28 | 29 | 30 | 31 | 95,145d 32 | 45,15d 33 | 34 | wxRIGHT 35 | 10 36 | 37 | 38 | wxBOTTOM|wxGROW 39 | 1 40 | 41 | 42 | 43 | wxEXPAND 44 | 12d 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /PasswordDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Password 5 | 1 6 | 7 | 8 | wxVERTICAL 9 | 10 | 11 | 12 | 13 | wxTOP|wxLEFT|wxRIGHT 14 | 10 15 | 16 | 17 | 18 | wxALL|wxGROW 19 | 10 20 | 21 | 22 | 23 | wxHORIZONTAL 24 | 25 | 26 | 27 | 28 | wxRIGHT|wxALIGN_CENTRE_VERTICAL 29 | 10 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | wxLEFT|wxRIGHT 39 | 10 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 49 | 10 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Preferences.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 5 10 | 5 11 | 1 12 | 13 | 14 | 15 | 16 | wxALIGN_CENTRE_VERTICAL 17 | 18 | 19 | 20 | 21 | 1 22 | 23 | 24 | 25 | 26 | 27 | 28 | wxALIGN_CENTRE_VERTICAL 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | wxALIGN_CENTRE_VERTICAL 38 | 39 | 40 | 41 | 42 | 1 43 | 44 | 45 | 46 | 47 | 48 | 49 | wxALIGN_CENTRE_VERTICAL 50 | 51 | 52 | 53 | wxALL|wxEXPAND 54 | 55 | 56 | 57 | wxALL|wxEXPAND|wxGROW 58 | 10 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /PreferencesDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Preferences 5 | 200,200d 6 | 7 | 8 | wxVERTICAL 9 | 10 | 11 | 5,5d 12 | 13 | wxLEFT|wxRIGHT|wxEXPAND 14 | 10 15 | 150,100d 16 | 17 | 18 | 19 | wxHORIZONTAL 20 | 21 | 22 | 23 | 24 | 25 | 26 | 50,180d 27 | 28 | wxLEFT|wxRIGHT 29 | 10 30 | 31 | 32 | 33 | 34 | 100,180d 35 | 36 | 37 | 38 | 39 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 40 | 10 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /README.V2: -------------------------------------------------------------------------------- 1 | Development has moved to https://github.com/andreas-p/admin4, as are the release files. 2 | 3 | The following information is deprecated, please visit https://github.com/andreas-p/admin4/releases for the current 4 | V3 version. 5 | 6 | ---------------------------------------------------------------------------------------------------------- 7 | For complete packages suitable for your platform, see the Vn.n.n directories. 8 | - Windows users: unzip the zip file and move the directory where you like and execute admin4.exe 9 | - Mac users: mount the dmg and move the app where you like. 10 | It might be necessary to right click Admin4 and select "Open" when starting it the first time, dependent on your security settings. 11 | If you continue to have problems starting Admin4, please report it here: https://github.com/andreas-p/admin4/issues/2 12 | - other systems: no packages available yet, use the source and install required python runtime and modules. 13 | Installation instructions and further documentation can be found at http://www.admin4.org/docs 14 | 15 | The Updates directory contains minor releases with bug fixes and additions based on major Vn.n.n files. 16 | It's recommended to use the online update feature which will automatically do the right thing, but you also can download a file and install it manually. 17 | 18 | Please note that most programming is performed on OSX, so if you encounter some strange behaviour on other platforms please don't hesitate to give feedback. 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](Admin4.ico) 3 | 4 | # Admin4 5 | 6 | Admin4 is a tool for server maintenance via several plugin modules, running on Windows, 7 | Mac OSX, Linux and many more platforms. Currently, plugins for BIND DNS, LDAP, IMAP 8 | and PostgreSQL are included. It is designed as a framework, using Python 9 | for fast development of plugins and custom modifications. 10 | 11 | 12 | ## Features 13 | 14 | The **Bind DNS** plugin supports browsing and editing of DNS zones. 15 | The plugin should be able to query (axfr) any type of server, and 16 | performs updates via DDNS which insures that it won't interfere with other 17 | DDNS clients (DHCP, SAMBA4). For Bind 9.7 and up, statistics are supported 18 | as well and used to retrieve the server's zones automatically. 19 | 20 | The **LDAP** plugin features browsing and generic editing of all types of 21 | LDAP entries with schema support. In addition, high-level editing of objects 22 | like users, groups and samba domains is supported. Custom objectClasses and attributes 23 | can easily be added. The goal of the plugin was to replace the 24 | windows-only ldapadmin tool with a portable solution. 25 | 26 | The **IMAP** plugin supports browsing and maintaining of mailboxes 27 | for standard IMAP4 mail storage servers. In is an everyday replacement 28 | for cyradm for Cyrus IMAPD servers, and should work with other implementations too. 29 | 30 | The **PostgreSQL** plugin features a nice query tool, a data modification tool 31 | and an object browser. It's aimed to replace pgAdmin3/pgAdmin4 with a modified feature 32 | set targeted at professionals. It supports gui editing only for common tasks 33 | and objects to keep the GUI lean, and emphasizes on features that increase productivity 34 | like object favorites, sql snippets and filter presets. 35 | 36 | ## Implementation 37 | 38 | Python3.7+ 39 | wxPython 4.1+ 40 | 41 | ## Website 42 | 43 | https://admin4.org 44 | 45 | 46 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | ## core 4 | 5 | - hide password preference 6 | 7 | - SSL certificate management 8 | 9 | ## modImap 10 | 11 | - check mailbox move target name 12 | - get/set other annotations for mailbox and server (no plans) 13 | 14 | 15 | ## modLdap 16 | 17 | #### New Object 18 | - default values preferences 19 | 20 | ignoreCert: 21 | ldap.OPT_X_TLS_ALLOW 22 | 23 | checkCert: 24 | - ldap.set_option(ldap.OPT_X_TLS_NEWCTX,ldap.OPT_X_TLS_DEMAND) 25 | - ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_DEMAND) 26 | - ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,certfile) 27 | 28 | #### objectClasses 29 | 30 | - mailGroup/member 31 | - groupOfUniqueNames/uniqueMember 32 | 33 | #### ToFix 34 | 35 | - PrimaryGroupSid 36 | - Group add description/displayname in list 37 | - deleteObjClass: remove attribs 38 | - nach rename refresh (2nd rename fails) 39 | - user.scs doppelt 40 | 41 | ## modPg 42 | 43 | ####Browser 44 | 45 | - update Favorites when deleting on 46 | - Triggers 47 | - Edit Table: Table, Column 48 | 49 | #### DataGrid 50 | 51 | - Drag/drop not from MouseDown for wx>3.0 52 | - OnFilterValidate and executeQuery catch error w/o logging 53 | - FK drilldown 54 | - float edit 55 | 56 | ShowBusy abort enable 57 | 58 | ResetPerspective 59 | 60 | ## modBind 61 | 62 | Check sanity of PTR data 63 | -------------------------------------------------------------------------------- /UpdateDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Update 5 | 1 6 | 7 | 8 | wxVERTICAL 9 | 10 | 11 | 12 | 13 | 14 | 15 | 2 16 | 17 | 18 | 19 | 20 | wxLEFT|wxALIGN_CENTRE_VERTICAL 21 | 10 22 | 23 | 24 | 25 | 26 | 27 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT 28 | 10 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | wxVERTICAL 38 | 39 | 40 | wxHORIZONTAL 41 | 42 | 43 | 44 | 45 | wxLEFT|wxALIGN_CENTRE_VERTICAL 46 | 10 47 | 48 | 49 | 50 | wxALL 51 | 10 52 | 100,-1d 53 | 54 | 55 | 56 | 57 | 12,12d 58 | 59 | wxRIGHT|wxALIGN_CENTRE_VERTICAL 60 | 10 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | wxLEFT|wxRIGHT|wxEXPAND 69 | 10 70 | 71 | 72 | 73 | 74 | wxVERTICAL 75 | 76 | 77 | 150, 85d 78 | 79 | 80 | 81 | wxEXPAND 82 | 150, 55d 83 | 84 | 85 | 86 | wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 87 | 10 88 | 89 | 90 | 91 | wxHORIZONTAL 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | wxLEFT|wxRIGHT 100 | 10 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 110 | 10 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /admin4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # The Admin4 Project 3 | # (c) 2013-2025 Andreas Pflug 4 | # 5 | # Licensed under the Apache License, 6 | # see LICENSE.TXT for conditions of usage 7 | 8 | if __name__ == "__main__": 9 | import sys, os 10 | 11 | loaddir=os.path.dirname(os.path.abspath(sys.argv[0])) 12 | sys.path.insert(0, loaddir) 13 | from main import main 14 | main(sys.argv) 15 | -------------------------------------------------------------------------------- /close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/close.png -------------------------------------------------------------------------------- /close_inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/close_inactive.png -------------------------------------------------------------------------------- /connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/connect.png -------------------------------------------------------------------------------- /delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/delete.png -------------------------------------------------------------------------------- /detach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/detach.png -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | # 7 | 8 | 9 | FROM python:3.11.4-slim-bookworm 10 | 11 | RUN apt-get update && \ 12 | apt-get install -y --no-install-recommends \ 13 | wget python3-pip build-essential libgtk-3-dev python3-wxgtk4.0 \ 14 | python3-requests python3-dnspython python3-ldap python3-psycopg2 && \ 15 | apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ 16 | useradd -u 1000 admin4 17 | 18 | COPY admin4/ /admin4/ 19 | 20 | WORKDIR /admin4 21 | ENV PYTHONPATH=/usr/local/lib/python3.11/site-packages:/usr/lib/python3/dist-packages 22 | CMD python3 admin4.py 23 | -------------------------------------------------------------------------------- /docker/admin4: -------------------------------------------------------------------------------- 1 | ../. -------------------------------------------------------------------------------- /docker/build-container.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # The Admin4 Project 4 | # (c) 2013-2022 Andreas Pflug 5 | # 6 | # Licensed under the Apache License, 7 | # see LICENSE.TXT for conditions of usage 8 | 9 | cd .. 10 | python3 createBundle.py docker 11 | -------------------------------------------------------------------------------- /docker/debug-container.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # The Admin4 Project 4 | # (c) 2013-2022 Andreas Pflug 5 | # 6 | # Licensed under the Apache License, 7 | # see LICENSE.TXT for conditions of usage 8 | 9 | if [ -z "$(xhost | grep LOCAL:)" ] ; then 10 | # allow local access 11 | xhost local:root 12 | fi 13 | 14 | # defaults to local image 15 | image=${1-adminfour/admin4:latest} 16 | shift 17 | 18 | IFS=":" read user _pwd uid gid _name home _shell <<< $(grep ^$(whoami): /etc/passwd) 19 | 20 | docker run -ti --rm --name admin4 $* \ 21 | --net=host --env=DISPLAY=unix$DISPLAY \ 22 | --volume /tmp/.X11-unix:/tmp/.X11-unix \ 23 | --volume /etc/passwd:/etc/passwd \ 24 | --volume $PWD/..:/src \ 25 | --volume $home:$home \ 26 | --user $uid:$gid \ 27 | $image /bin/bash 28 | 29 | -------------------------------------------------------------------------------- /docker/push-container.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | tag=${1-$(git tag | tail -1)} 3 | docker push adminfour/admin4:$tag 4 | docker push adminfour/admin4:latest 5 | -------------------------------------------------------------------------------- /docker/run-container.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # The Admin4 Project 4 | # (c) 2013-2022 Andreas Pflug 5 | # 6 | # Licensed under the Apache License, 7 | # see LICENSE.TXT for conditions of usage 8 | 9 | if [ -z "$(xhost | grep LOCAL:)" ] ; then 10 | # allow local access 11 | xhost local:root 12 | fi 13 | 14 | image=${1-adminfour/admin4:latest} 15 | IFS=":" read user _pwd uid gid _name home _shell <<< $(grep ^$(whoami): /etc/passwd) 16 | 17 | docker run -ti --rm --name admin4 \ 18 | --net=host --env=DISPLAY=unix$DISPLAY \ 19 | --volume /tmp/.X11-unix:/tmp/.X11-unix \ 20 | --volume /etc/passwd:/etc/passwd \ 21 | --volume $home:$home \ 22 | --user $uid:$gid \ 23 | $image 24 | 25 | -------------------------------------------------------------------------------- /edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/edit.png -------------------------------------------------------------------------------- /edit_find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/edit_find.png -------------------------------------------------------------------------------- /find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/find.png -------------------------------------------------------------------------------- /folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/folder.png -------------------------------------------------------------------------------- /logger.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | import time, traceback 9 | 10 | loglines=[] 11 | querylines=[] 12 | queryfile=None 13 | logfile=None 14 | 15 | class LOGLEVEL: 16 | NONE=0 17 | DEBUG=1 18 | INFO=2 19 | ERROR=3 20 | CRIT=4 21 | @staticmethod 22 | def Text(level): 23 | return ["None", "Debug", "Info", "Error", "Critical"][level] 24 | loglevel=LOGLEVEL.NONE 25 | querylevel=LOGLEVEL.NONE 26 | 27 | 28 | class _Line: 29 | def __init__(self): 30 | self.timestamp=time.time() 31 | 32 | def Timestamp(self): 33 | return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.timestamp)) 34 | 35 | def LevelText(self): 36 | return LOGLEVEL.Text(self.level) 37 | 38 | def LevelImageId(self): 39 | from adm import images 40 | if self.level: 41 | return images.GetId(self.LevelText()) 42 | return -1 43 | 44 | def __getitem__(self, name): 45 | return self.__dict__.get(name) 46 | 47 | 48 | 49 | class LogLine(_Line): 50 | def __init__(self, level, text, tb=None): 51 | _Line.__init__(self) 52 | self.level=level 53 | self.text=text 54 | self.tb=tb 55 | 56 | 57 | 58 | class QueryLine(_Line): 59 | def __init__(self, level, cmd, error=None, result=None): 60 | _Line.__init__(self) 61 | self.level=level 62 | indent=-1 63 | lines=[] 64 | if cmd: 65 | for line in cmd.splitlines(): 66 | line=line.rstrip() 67 | sline=line.lstrip() 68 | if not len(sline): 69 | continue 70 | if indent < 0: 71 | indent = len(line)-len(sline) 72 | lines.append(sline) 73 | else: 74 | ind=len(line)-len(sline) -indent 75 | empty="" 76 | for _i in range(ind): 77 | empty += " " 78 | lines.append(empty + sline) 79 | self.cmd = "\n".join(lines) 80 | self.error=error 81 | self.result=result 82 | 83 | 84 | def __getitem__(self, name): 85 | if name == 'err+result': 86 | if self.error: 87 | if self.result: 88 | return "%s - %s" % (self.error, self.result) 89 | else: 90 | return self.error 91 | return self.result 92 | return self.__dict__.get(name) 93 | 94 | 95 | if False: 96 | loglines.append( LogLine(LOGLEVEL.DEBUG, "Debug message", None)) 97 | loglines.append( LogLine(LOGLEVEL.INFO, "info message", None)) 98 | loglines.append( LogLine(LOGLEVEL.ERROR, "error message", None)) 99 | loglines.append( LogLine(LOGLEVEL.CRIT, "critical message", None)) 100 | querylines.append( QueryLine(LOGLEVEL.DEBUG, "Debug message", None, "Some weird result")) 101 | querylines.append( QueryLine(LOGLEVEL.ERROR, "error message", "Some failure", None)) 102 | 103 | 104 | 105 | def _log(level, fmt, args, tb=None): 106 | if level < loglevel and not tb: 107 | return 108 | 109 | txt=fmt % args 110 | line=LogLine(level, txt, tb) 111 | loglines.append(line) 112 | 113 | if logfile: 114 | try: 115 | f=open(logfile, 'a') 116 | f.write("%s %s: %s\n" % (line.Timestamp(), line.LevelText(), txt)) 117 | if tb: 118 | f.write("%s\n" % tb) 119 | except Exception as e: 120 | print ("CANNOT LOG", e) 121 | pass 122 | 123 | 124 | def trace(offset, level, fmt, *args): 125 | if True: 126 | txt=fmt % args 127 | stack=traceback.extract_stack() 128 | lst=[] 129 | for i in range(len(stack)-offset, len(stack)-offset-level, -1): 130 | file=stack[i][0].split('/')[-1] 131 | lst.append("%s (%s:%d)" % (stack[i][2], file, stack[i][1])) 132 | print (txt, "Stack:", " ".join(lst)) 133 | 134 | def debug(fmt, *args): 135 | _log(LOGLEVEL.DEBUG, fmt, args) 136 | 137 | def error(fmt, *args): 138 | _log(LOGLEVEL.ERROR, fmt, args) 139 | 140 | def exception(fmt, *args): 141 | """ 142 | exception(formatStr, [args]) 143 | 144 | logs error and exception traceback 145 | """ 146 | _log(LOGLEVEL.ERROR, fmt, args, traceback.format_exc()) 147 | 148 | def sysexception(extype, args, tb): 149 | try: txtargs= " ".join(args) 150 | except: txtargs="" 151 | try: txttb="".join(traceback.format_tb(tb)) 152 | except: txttb="" 153 | _log(LOGLEVEL.ERROR, "%s: %s %s", (extype.__name__, txtargs, txttb)) 154 | 155 | def querylog(cmd, result=None, error=None): 156 | cmd=str(cmd) 157 | line=None 158 | if querylevel > LOGLEVEL.DEBUG or error: 159 | line=QueryLine(LOGLEVEL.ERROR, cmd, error, result) 160 | elif querylevel == LOGLEVEL.DEBUG: 161 | line=QueryLine(LOGLEVEL.DEBUG, cmd, error, result) 162 | if line: 163 | querylines.append(line) 164 | 165 | global queryfile 166 | if queryfile: 167 | try: 168 | f=open(queryfile, 'a') 169 | f.write(line.cmd) 170 | f.write("\n\n") 171 | f.close() 172 | except: 173 | _log(LOGLEVEL.ERROR, "Query Log File %s cannot be written.", queryfile) 174 | queryfile=None 175 | -------------------------------------------------------------------------------- /modBind/CatalogHostRecord.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A/AAAA Record 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 80,-1d 18 | 19 | 20 | 21 | 22 | 23 | 5,7d 24 | 25 | 26 | 27 | 28 | 50,5d 29 | 30 | 150,35d 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 40,-1d 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 40,-1d 52 | 53 | 54 | 10 55 | 10 56 | 57 | wxALL 58 | 10 59 | 60 | 61 | 62 | wxHORIZONTAL 63 | 64 | 65 | wxEXPAND 66 | 67 | 68 | 69 | 70 | 40,130d 71 | 45,-1d 72 | 73 | wxRIGHT 74 | 10 75 | 76 | 77 | 78 | 79 | 95,130d 80 | 45,-1d 81 | 82 | 83 | 84 | 85 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 86 | 10 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /modBind/CatalogMemberRecord.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DNS Record 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 80,-1d 18 | 19 | 20 | 21 | 22 | 23 | 5,7d 24 | 25 | 26 | 27 | 28 | 50,5d 29 | 80,-1d 30 | 31 | wxGROW 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 40,-1d 41 | 42 | 43 | 10 44 | 10 45 | 1 46 | 47 | wxALL|wxEXPAND|wxGROW 48 | 10 49 | 50 | 51 | 52 | wxHORIZONTAL 53 | 54 | 55 | wxEXPAND 56 | 57 | 58 | 59 | 60 | 40,130d 61 | 45,-1d 62 | 63 | wxRIGHT 64 | 10 65 | 66 | 67 | 68 | 69 | 95,130d 70 | 45,-1d 71 | 72 | 73 | 74 | 75 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 76 | 10 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /modBind/CatalogZone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modBind/CatalogZone.png -------------------------------------------------------------------------------- /modBind/HOWTO: -------------------------------------------------------------------------------- 1 | 2 | named.conf: 3 | 4 | acl "admin4" { 5 | key "rndc-key"; 6 | }; 7 | 8 | # BIND 9.7+ 9 | statistics-channels { 10 | inet * port 8053 11 | allow { 127.0.0.1; 192.168.0.0/24; }; 12 | }; 13 | 14 | zones: 15 | allow-transfer { admin4; }; 16 | allow-update { admin4; }; 17 | 18 | -------------------------------------------------------------------------------- /modBind/HostRecord.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A/AAAA Record 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 80,-1d 18 | 19 | 20 | 21 | 22 | 23 | 5,7d 24 | 25 | 26 | 27 | 28 | 50,5d 29 | 30 | 150,35d 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 40,-1d 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 40,-1d 52 | 53 | 54 | 55 | 56 | 57 | 5,112d 58 | 59 | 60 | 61 | 62 | 63 | 1 64 | 50,112d 65 | 66 | 67 | 10 68 | 10 69 | 70 | wxALL 71 | 10 72 | 73 | 74 | 75 | wxHORIZONTAL 76 | 77 | 78 | wxEXPAND 79 | 80 | 81 | 82 | 83 | 40,130d 84 | 45,-1d 85 | 86 | wxRIGHT 87 | 10 88 | 89 | 90 | 91 | 92 | 95,130d 93 | 45,-1d 94 | 95 | 96 | 97 | 98 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 99 | 10 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /modBind/MultiValRecords.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DNS Record 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 80,-1d 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 40,-1d 28 | 29 | 30 | 10 31 | 10 32 | 1 33 | 34 | wxALL 35 | 10 36 | 37 | 38 | 39 | 50,5d 40 | 120,40d 41 | 42 | 43 | wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND|wxGROW 44 | 20 45 | 46 | 47 | 48 | wxHORIZONTAL 49 | 50 | 51 | wxEXPAND 52 | 53 | 54 | 55 | 56 | 40,130d 57 | 45,-1d 58 | 59 | wxRIGHT 60 | 10 61 | 62 | 63 | 64 | 65 | 95,130d 66 | 45,-1d 67 | 68 | 69 | 70 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 71 | 10 72 | 73 | 74 | 75 | wxEXPAND|wxGROW 76 | 10d 77 | 78 | 79 | 150,110d 80 | 81 | 82 | -------------------------------------------------------------------------------- /modBind/RevZone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modBind/RevZone.png -------------------------------------------------------------------------------- /modBind/Server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modBind/Server.png -------------------------------------------------------------------------------- /modBind/SingleValRecord.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DNS Record 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 80,-1d 18 | 19 | 20 | 21 | 22 | 23 | 5,7d 24 | 25 | 26 | 27 | 28 | 50,5d 29 | 80,-1d 30 | 31 | wxGROW 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 40,-1d 41 | 42 | 43 | 10 44 | 10 45 | 1 46 | 47 | wxALL|wxEXPAND|wxGROW 48 | 10 49 | 50 | 51 | 52 | wxHORIZONTAL 53 | 54 | 55 | wxEXPAND 56 | 57 | 58 | 59 | 60 | 40,130d 61 | 45,-1d 62 | 63 | wxRIGHT 64 | 10 65 | 66 | 67 | 68 | 69 | 95,130d 70 | 45,-1d 71 | 72 | 73 | 74 | 75 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 76 | 10 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /modBind/SingleValRecords.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DNS Record 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 80,-1d 18 | 19 | 20 | 21 | 22 | 23 | 5,7d 24 | 25 | 26 | 27 | 28 | 50,5d 29 | 80,35d 30 | 31 | 32 | wxRIGHT|wxEXPAND|wxGROW 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 40,-1d 42 | 43 | 44 | 10 45 | 10 46 | 1 47 | 48 | wxALL|wxEXPAND|wxGROW 49 | 10 50 | 51 | 52 | 53 | wxHORIZONTAL 54 | 55 | 56 | wxEXPAND 57 | 58 | 59 | 60 | 61 | 40,130d 62 | 45,-1d 63 | 64 | wxRIGHT 65 | 10 66 | 67 | 68 | 69 | 70 | 95,130d 71 | 45,-1d 72 | 73 | 74 | 75 | 76 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 77 | 10 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /modBind/Zone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modBind/Zone.png -------------------------------------------------------------------------------- /modBind/Zone.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DNS Zone 5 | 6 | 7 | 5,7d 8 | 9 | 10 | 50,5d 11 | 80,-1d 12 | 13 | 14 | 15 | 5,22d 16 | 17 | 18 | 50,20d 19 | 80,-1d 20 | 21 | 22 | 23 | 24 | 5,37d 25 | 26 | 27 | 50,35d 28 | 80,-1d 29 | 30 | 31 | 32 | 33 | 5,52d 34 | 35 | 36 | 50,50d 37 | 80,-1d 38 | 39 | 40 | 41 | 5,67d 42 | 43 | 44 | 45 | 1 46 | 50,67d 47 | 48 | 49 | 50 | 40,100d 51 | 45,-1d 52 | 53 | 54 | 55 | 95,100d 56 | 45,-1d 57 | 58 | 150,120d 59 | 60 | -------------------------------------------------------------------------------- /modBind/__init__.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2025 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | moduleinfo={ 'name': "BIND DNS Server", 8 | 'modulename': "BIND", 9 | 'description': "BIND9 DNS server", 10 | 'version': "9.18", 11 | 'revision': "0.99.10", 12 | 'requiredAdmVersion': "3.0.0", 13 | 'testedAdmVersion': "3.0.0", 14 | 'supports': "BIND V9.6 ... V9.18", 15 | 'copyright': "(c) 2014-2025 PSE Consulting Andreas Pflug", 16 | 'credits': "dnspython from http://www.dnspython.org", 17 | } 18 | 19 | import sys 20 | if not hasattr(sys, 'skipSetupInit'): 21 | from . import Server 22 | 23 | -------------------------------------------------------------------------------- /modBind/_requires.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | # Mac OSX 10.8, 10.9: 9 | # xcode-select --install 10 | # sudo easy_install pip 11 | # sudo pip install dnspython 12 | # sudo pip install requests 13 | # 14 | # Debian: 15 | # apt-get install python-dnspython python-requests 16 | # 17 | # Windows: 18 | # http://www.dnspython.org 19 | # http://www.python-requests.org 20 | 21 | 22 | def GetPrerequisites(info=False): 23 | try: 24 | import dns.version 25 | if dns.version.version < "2.0.": 26 | if info: 27 | print ("dnspython too old") 28 | return None 29 | return "dns requests" 30 | except: 31 | if info: 32 | print ("dnspython missing") 33 | pass 34 | return None 35 | -------------------------------------------------------------------------------- /modImap/Mailbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modImap/Mailbox.png -------------------------------------------------------------------------------- /modImap/MailboxAcl.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | wxVERTICAL 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 2 20 | 2 21 | 22 | 23 | wxVERTICAL 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | wxEXPAND 32 | 33 | 34 | 35 | 36 | 37 | wxTOP 38 | 5d 39 | 40 | 41 | 42 | 43 | 44 | wxTOP 45 | 5d 46 | 47 | 48 | 49 | 50 | 51 | wxTOP 52 | 5d 53 | 54 | 55 | 56 | 57 | 58 | wxTOP 59 | 5d 60 | 61 | 62 | 63 | wxEXPAND 64 | 65 | 66 | 67 | 68 | 120,150d 69 | 70 | 71 | wxEXPAND|wxGROW 72 | 73 | 5d 74 | 5d 75 | 1 76 | 1 77 | 78 | 79 | wxTOP|wxLEFT|wxRIGHT|wxEXPAND 80 | 5d 81 | 82 | 83 | 84 | wxHORIZONTAL 85 | 86 | 87 | wxEXPAND 88 | 89 | 90 | 91 | 92 | 40,130d 93 | 45,-1d 94 | 95 | wxRIGHT 96 | 10 97 | 98 | 99 | 100 | 101 | 95,130d 102 | 45,-1d 103 | 104 | 105 | 106 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 107 | 10 108 | 109 | 110 | 12,12d 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /modImap/MailboxNoselect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modImap/MailboxNoselect.png -------------------------------------------------------------------------------- /modImap/Server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modImap/Server.png -------------------------------------------------------------------------------- /modImap/Server.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | import adm 8 | from wh import xlt, YesNo 9 | from ._imap import ImapServer 10 | 11 | class Server(adm.ServerNode): 12 | shortname=xlt("IMAP4 Server") 13 | typename=xlt("IMAP4 Server") 14 | # findObjectIncremental=False 15 | 16 | 17 | def __init__(self, settings): 18 | adm.ServerNode.__init__(self, settings) 19 | self.userList=[] 20 | self.mailboxPath="" 21 | 22 | def IsConnected(self, _deep=False): 23 | return self.connection != None 24 | 25 | 26 | def Disconnect(self): 27 | if self.connection: 28 | self.connection.logout() 29 | self.connection=None 30 | 31 | 32 | def DoConnect(self): 33 | if not self.connection: 34 | self.connection=ImapServer.Create(self) 35 | self.connection.Login(self.user, self.password) 36 | self.flavor=self.connection.id.get('name', '').split()[0].lower() 37 | return self.connection 38 | 39 | 40 | def GetLastError(self): 41 | if self.connection and not self.connection.ok(): 42 | return self.connection.lastError 43 | return None 44 | 45 | 46 | def GetProperties(self): 47 | if not self.properties: 48 | sec=self.settings['security'] 49 | if sec.startswith('SSL'): 50 | pass 51 | elif sec.startswith('TLS'): 52 | if self.connection.tls: sec="TLS" 53 | else: sec=xlt("unsecured connection") 54 | 55 | self.annotations=self.connection.GetAnnotations("") 56 | 57 | self.properties= [ 58 | ( xlt("Name"),self.name), 59 | ( xlt("Protocol"), self.connection.PROTOCOL_VERSION), 60 | ( xlt("Address"), self.address), 61 | ( xlt("Security"), sec), 62 | ( xlt("Port"), self.settings["port"]), 63 | ( xlt("User"), self.user), 64 | ( xlt("Connected"), YesNo(self.IsConnected())), 65 | ( xlt("Autoconnect"), YesNo(self.settings.get('autoconnect'))), 66 | ] 67 | self.AddProperty("Server", self.connection.id.get('name')) 68 | self.AddProperty("Version", self.connection.id.get('version')) 69 | if self.annotations: 70 | fs=self.annotations.Get('/freespace') 71 | if fs != None: 72 | self.AddSizeProperty(xlt("Free space"), float(fs)*1024) 73 | 74 | # if self.IsConnected(): 75 | # self.AddChildrenProperty(list(self.connection.capabilities), xlt("Capabilities"), -1) 76 | return self.properties 77 | 78 | 79 | class Dlg(adm.ServerPropertyDialog): 80 | def __init__(self, parentWin, node): 81 | adm.PropertyDialog.__init__(self, parentWin, node, None) 82 | self['Security'].Append( { ' ': xlt("No security"), 'TLS-req': xlt("TLS required"), 'TLS-pref': xlt("TLS if available"), 'SSL': xlt("SSL") } ) 83 | self.Bind("HostName HostAddress Port User Password Autoconnect") 84 | self.Bind("Security", self.OnChangeSecurity) 85 | 86 | def OnChangeSecurity(self, _evt): 87 | if self.security == "SSL": 88 | self.port=993 89 | else: 90 | self.port=143 91 | 92 | self.Check() 93 | 94 | def Go(self): 95 | if self.node: 96 | self.SetSettings(self.node.settings) 97 | self["HostName"].Disable() 98 | else: 99 | self.Security="TLS-req" 100 | self.OnCheck() 101 | 102 | def Check(self): 103 | ok=True 104 | if not self.node: 105 | ok=self.CheckValid(ok, self.Hostname, xlt("Host name cannot be empty")) 106 | ok=self.CheckValid(ok, not adm.config.existsServer(self, self.HostName), xlt("Host name already in use")) 107 | ok=self.CheckValid(ok, self.HostAddress, xlt("Host address cannot be empty")) 108 | ok=self.CheckValid(ok, self.Port, xlt("Port cannot be 0")) 109 | return ok 110 | 111 | def Save(self): 112 | if self.GetChanged(): 113 | settings=self.GetSettings() 114 | adm.config.storeServerSettings(self, settings) 115 | if self.node: 116 | self.node.settings=settings 117 | self.node.registrationChanged=True 118 | else: 119 | adm.RegisterServer(settings) 120 | return True 121 | 122 | @staticmethod 123 | def Register(parentWin): 124 | adm.DisplayDialog(Server.Dlg, parentWin, None) 125 | 126 | def Edit(self, parentWin): 127 | adm.DisplayDialog(Server.Dlg, parentWin, self) 128 | 129 | nodeinfo=[ { 'class': Server, 'collection': xlt("IMAP4 Server") } ] 130 | 131 | -------------------------------------------------------------------------------- /modImap/Server.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PostgreSQL Server 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 5,7d 14 | 15 | 16 | 17 | 18 | 50,5d 19 | 80,-1d 20 | 21 | 22 | 23 | 24 | 25 | 5,22d 26 | 27 | 28 | 29 | 30 | 50,20d 31 | 80,-1d 32 | 33 | 34 | 35 | 36 | 37 | 5,37d 38 | 39 | 40 | 41 | 42 | 50,37d 43 | 44 | 45 | 46 | 47 | 48 | 5,52d 49 | 50 | 51 | 52 | 53 | 50,50d 54 | 143 55 | 35,-1d 56 | 57 | 58 | 59 | 60 | 61 | 5,82d 62 | 63 | 64 | 65 | 66 | 50,80d 67 | root 68 | 80,-1d 69 | 70 | 71 | 72 | 73 | 74 | 5,97d 75 | 76 | 77 | 78 | 79 | 50,95d 80 | 80,-1d 81 | 82 | 83 | 84 | 85 | 86 | 5,112d 87 | 88 | 89 | 90 | 91 | 92 | 1 93 | 50,112d 94 | 95 | 96 | 10 97 | 10 98 | 99 | wxALL 100 | 10 101 | 102 | 103 | 104 | wxHORIZONTAL 105 | 106 | 107 | wxEXPAND 108 | 109 | 110 | 111 | 112 | 40,130d 113 | 45,-1d 114 | 115 | wxRIGHT 116 | 10 117 | 118 | 119 | 120 | 121 | 95,130d 122 | 45,-1d 123 | 124 | 125 | 126 | 127 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 128 | 10 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /modImap/User.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modImap/User.png -------------------------------------------------------------------------------- /modImap/__init__.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | moduleinfo={ 'name': "IMAP Server", 9 | 'modulename': "IMAP", 10 | 'description': "IMAP server", 11 | 'version': "4", 12 | 'revision': "0.8.7", 13 | 'requiredAdmVersion': "3.0.0", 14 | 'testedAdmVersion': "3.0.0", 15 | 'pages': [], 16 | 'copyright': "(c) 2014-2022 PSE Consulting Andreas Pflug", 17 | 'credits': "utf-7 code from https://pypi.python.org/pypi/IMAPClient", 18 | } 19 | 20 | 21 | import sys 22 | if not hasattr(sys, 'skipSetupInit'): 23 | from . import Server -------------------------------------------------------------------------------- /modImap/_requires.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | def GetPrerequisites(_info=False): 8 | return "imaplib" 9 | -------------------------------------------------------------------------------- /modImap/imap_utf7.py: -------------------------------------------------------------------------------- 1 | # The contents of this file has been derived code from the Twisted project 2 | # (http://twistedmatrix.com/). The original author is Jp Calderone. 3 | 4 | # Twisted project license follows: 5 | 6 | # Permission is hereby granted, free of charge, to any person obtaining 7 | # a copy of this software and associated documentation files (the 8 | # "Software"), to deal in the Software without restriction, including 9 | # without limitation the rights to use, copy, modify, merge, publish, 10 | # distribute, sublicense, and/or sell copies of the Software, and to 11 | # permit persons to whom the Software is furnished to do so, subject to 12 | # the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be 15 | # included in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | # Modified for Pytho3: using str only 27 | 28 | class FolderNameError(ValueError): 29 | pass 30 | 31 | 32 | stdPattern=list(range(0x20, 0x2)) + list(range(0x27, 0x7f)) 33 | def encode(s): 34 | if isinstance(s, str) and sum(n for n in (ord(c) for c in s) if n > 127): 35 | raise FolderNameError("%r contains characters not valid in a str folder name. " 36 | "Convert to unicode first?" % s) 37 | 38 | r = [] 39 | _in = [] 40 | for c in s: 41 | if ord(c) in stdPattern: 42 | if _in: 43 | r.extend(['&', modified_base64(''.join(_in)), '-']) 44 | del _in[:] 45 | r.append(str(c)) 46 | elif c == '&': 47 | if _in: 48 | r.extend(['&', modified_base64(''.join(_in)), '-']) 49 | del _in[:] 50 | r.append('&-') 51 | else: 52 | _in.append(c) 53 | if _in: 54 | r.extend(['&', modified_base64(''.join(_in)), '-']) 55 | return ''.join(r) 56 | 57 | 58 | def decode(s): 59 | r = [] 60 | decode = [] 61 | for c in s: 62 | if c == '&' and not decode: 63 | decode.append('&') 64 | elif c == '-' and decode: 65 | if len(decode) == 1: 66 | r.append('&') 67 | else: 68 | r.append(modified_unbase64(''.join(decode[1:]))) 69 | decode = [] 70 | elif decode: 71 | decode.append(c) 72 | else: 73 | r.append(c) 74 | if decode: 75 | r.append(modified_unbase64(''.join(decode[1:]))) 76 | out = ''.join(r) 77 | 78 | # if not isinstance(out, str): 79 | # out =out.decode('latin-1') 80 | return out 81 | 82 | 83 | def modified_base64(s): 84 | s_utf7 = s.encode('utf-7').decode() 85 | return s_utf7[1:-1].replace('/', ',') 86 | 87 | 88 | def modified_unbase64(s): 89 | s_utf7 = '+' + s.replace(',', '/') + '-' 90 | return s_utf7.encode().decode('utf-7') 91 | -------------------------------------------------------------------------------- /modLdap/Computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/Computer.png -------------------------------------------------------------------------------- /modLdap/Contact.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 100,20d 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 100,20d 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 100,20d 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 100,-1d 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 100,-1d 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 150,30d 71 | 72 | 73 | 74 | 75 | 10 76 | 10 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | wxHORIZONTAL 85 | 86 | 87 | 40,-1d 88 | 89 | wxRIGHT 90 | 5d 91 | 92 | 93 | 94 | 105,-1d 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 150,-1d 107 | 108 | 109 | 1 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 150,30d 118 | 119 | 120 | 121 | 122 | 123 | wxALL|wxEXPAND 124 | 5 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /modLdap/Entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/Entry.png -------------------------------------------------------------------------------- /modLdap/GenericEntry.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 13 | wxSTRETCH_NOT|wxALIGN_CENTRE_VERTICAL|wxADJUST_MINSIZE|wxFIXED_MINSIZE 14 | 15 | 16 | 17 | wxBOTTOM|wxEXPAND|wxALIGN_CENTRE_VERTICAL 18 | 5 19 | 20 | 21 | 22 | 23 | 24 | wxRIGHT|wxSTRETCH_NOT|wxALIGN_CENTRE_VERTICAL|wxADJUST_MINSIZE|wxFIXED_MINSIZE 25 | 5 26 | 27 | 28 | 29 | wxHORIZONTAL 30 | 31 | 32 | 33 | <All> 34 | 35 | 0 36 | 50,-1d 37 | 38 | 39 | 40 | wxALIGN_CENTRE_VERTICAL 41 | 42 | 43 | 44 | 45 | 30,-1d 46 | 47 | wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL 48 | 5 49 | 50 | 51 | 52 | 53 | 30,-1d 54 | 55 | wxLEFT|wxALIGN_CENTRE_VERTICAL 56 | 5 57 | 58 | 59 | 60 | wxEXPAND 61 | 62 | 2 63 | 1 64 | 65 | 66 | wxTOP|wxLEFT|wxRIGHT|wxEXPAND 67 | 5 68 | 69 | 70 | 71 | 72 | wxALL|wxEXPAND 73 | 4 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /modLdap/Group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/Group.png -------------------------------------------------------------------------------- /modLdap/Group.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 80,-1d 17 | 18 | 19 | 10 20 | 10 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | wxHORIZONTAL 29 | 30 | 31 | 35,-1d 32 | 33 | 34 | 35 | 36 | wxEXPAND 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | wxEXPAND 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | wxEXPAND 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | wxEXPAND 65 | 66 | 1 67 | 68 | 69 | wxVERTICAL 70 | 71 | 72 | 73 | 74 | 75 | 76 | 0,0 77 | 78 | 79 | 80 | 81 | 82 | 35,-1d 83 | 84 | wxTOP|wxBOTTOM|wxALIGN_RIGHT 85 | 5 86 | 87 | 88 | 89 | 90 | 35,-1d 91 | 92 | wxALIGN_RIGHT 93 | 94 | 95 | 96 | wxEXPAND 97 | 98 | 99 | 100 | 101 | wxEXPAND 102 | 103 | 104 | wxALL|wxEXPAND 105 | 5 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /modLdap/Groups.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | 10 | wxALL 11 | 5 12 | 13 | 14 | 15 | 16 | wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND 17 | 5 18 | 19 | 20 | 21 | wxHORIZONTAL 22 | 23 | 24 | 25 | 45,-1d 26 | 27 | 28 | 29 | 30 | 31 | 45,-1d 32 | 33 | wxLEFT 34 | 5 35 | 36 | 37 | wxALL 38 | 5 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /modLdap/OrgUnit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/OrgUnit.png -------------------------------------------------------------------------------- /modLdap/Personal.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 100,20d 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 100,20d 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 100,-1d 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 150,40d 49 | 50 | 51 | 52 | 10 53 | 10 54 | 1 55 | 56 | wxALL 57 | 5 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /modLdap/Posix.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | nodeinfo=[] 9 | from .SpecificEntry import SpecificEntry 10 | from .Entry import Entry 11 | from wh import xlt 12 | import wx, adm 13 | 14 | 15 | class UserAccount(SpecificEntry): 16 | name=xlt("Account") 17 | typename=xlt("LDAP User Account") 18 | shortname=xlt("User") 19 | icon="User" 20 | canClasses="inetorgperson" 21 | startClasses="inetOrgPerson" 22 | 23 | @classmethod 24 | def GetClassIconName(self, node): 25 | if node.HasObjectClass("sambaSAMAccount"): 26 | return "SamUser" 27 | elif node.HasObjectClass("posixAccount"): 28 | return "PosixUser" 29 | return self.icon 30 | 31 | @staticmethod 32 | def New(parentWin, parentNode): 33 | adm.DisplayDialog(Entry.Dlg, parentWin, None, parentNode, UserAccount) 34 | 35 | SpecificEntry.AddClass(UserAccount) 36 | Entry.addNewEntryClass(UserAccount) 37 | 38 | 39 | 40 | class ShadowAccount(SpecificEntry): 41 | name=xlt("POSIX/Shadow") 42 | def __init__(self, dlg, notebook, resname=None): 43 | SpecificEntry.__init__(self, dlg, notebook, resname) 44 | self.Bind("Expires", wx.EVT_CHECKBOX, self.OnExpire) 45 | self.Bind("GenerateUid", self.OnGenerateUid) 46 | self.Bind("GenerateGid", self.OnGenerateGid) 47 | 48 | def Go(self): 49 | SpecificEntry.Go(self) 50 | self.OnExpire() 51 | 52 | def OnGenerateUid(self, evt): 53 | if self.GetIdFromMax("posixAccount", "uidNumber"): 54 | self['GenerateUid'].Disable() 55 | 56 | def OnGenerateGid(self, evt): 57 | if self.GetIdFromMax("posixAccount", "gidNumber"): 58 | self['GenerateGid'].Disable() 59 | 60 | 61 | def Check(self): 62 | ok=SpecificEntry.Check(self) 63 | 64 | if self.dialog.HasObjectClass("posixAccount"): 65 | if not self.uidNumber and self.GetServer().GetIdGeneratorStyle(): 66 | dn=self.GetServer().GetSambaUnixIdPoolDN() 67 | if not dn: 68 | if not self.dialog.HasObjectClass("sambaSamAccount"): 69 | ok=self.dialog.CheckValid(ok, dn, xlt("Need sambaUnixIdPoolDN configured for this server or Samba Account data")) 70 | 71 | return ok 72 | 73 | 74 | def OnExpire(self, ev=None): 75 | if self.shadowAccount: 76 | self.EnableControls("shadowExpire shadowWarning", self.Expires) 77 | if not self.Expires: 78 | self.shadowExpire=99999 79 | self.shadowWarning=None 80 | if ev: 81 | self.dialog.OnCheck() 82 | SpecificEntry.AddClass(ShadowAccount) 83 | 84 | 85 | 86 | class Contact(SpecificEntry): 87 | name=xlt("Contact") 88 | SpecificEntry.AddClass(Contact) 89 | 90 | class Personal(SpecificEntry): 91 | name=xlt("Personal") 92 | SpecificEntry.AddClass(Personal) 93 | 94 | -------------------------------------------------------------------------------- /modLdap/PosixUser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/PosixUser.png -------------------------------------------------------------------------------- /modLdap/Preferences.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 5,7d 7 | 8 | 9 | 80,5d 10 | 80,-1d 11 | 12 | 13 | 14 | 5,22d 15 | 16 | 17 | 18 | SSHA 19 | SMD5 20 | SHA 21 | MD5 22 | CLEARTEXT 23 | 24 | 0 25 | 80,20d 26 | 80,-1d 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /modLdap/SamUser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/SamUser.png -------------------------------------------------------------------------------- /modLdap/SambaDomain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/SambaDomain.png -------------------------------------------------------------------------------- /modLdap/SambaGroupMapping.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | 10 | wxTOP|wxLEFT 11 | 5 12 | 13 | 14 | 15 | 2 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 | wxALIGN_CENTRE_VERTICAL 41 | 42 | 43 | 44 | 45 | 10 46 | 10 47 | 48 | 49 | 50 | 51 | 52 | 1 53 | 54 | 55 | wxHORIZONTAL 56 | 57 | 58 | 40,-1d 59 | 60 | 61 | 62 | 63 | wxEXPAND 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | wxEXPAND 74 | 75 | 76 | wxTOP|wxLEFT|wxRIGHT|wxEXPAND 77 | 20 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /modLdap/Server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/Server.png -------------------------------------------------------------------------------- /modLdap/ServerConfig.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Server Configuration 5 | 150,120d 6 | 7 | wxVERTICAL 8 | 9 | 10 | 11 | 12 | 13 | 14 | wxRIGHT|wxALIGN_CENTRE 15 | 5 16 | 17 | 18 | 19 | 20 | wxLEFT|wxRIGHT|wxGROW 21 | 5 22 | 23 | 2 24 | 1 25 | 26 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 27 | 10 28 | 29 | 30 | 31 | 32 | 33 | currentMax+1 34 | smbldap-tools 35 | 36 | 37 | 38 | wxTOP|wxLEFT|wxRIGHT 39 | 10 40 | 41 | 42 | 43 | 44 | wxVERTICAL 45 | 46 | 47 | 5,20d 48 | 49 | 50 | wxBOTTOM|wxRIGHT|wxGROW 51 | 5 52 | 100,30d 53 | 54 | 55 | 56 | wxTOP|wxLEFT|wxRIGHT|wxGROW 57 | 10 58 | 59 | 60 | 61 | wxHORIZONTAL 62 | 63 | 64 | wxGROW 65 | 66 | 67 | 68 | 69 | 95,160d 70 | 45,-1d 71 | 72 | wxRIGHT 73 | 10 74 | 75 | 76 | 77 | 78 | 40,160d 79 | 45,-1d 80 | 81 | 82 | 83 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 84 | 10 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /modLdap/User.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/User.png -------------------------------------------------------------------------------- /modLdap/UserAccount.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 80,-1d 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 80,-1d 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | wxALIGN_CENTRE_VERTICAL 37 | 38 | 10 39 | 10 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | wxHORIZONTAL 56 | 57 | 58 | 80,-1d 59 | 60 | 61 | 62 | 63 | 64 | 65 | wxLEFT|wxALIGN_CENTRE_VERTICAL 66 | 20 67 | 68 | 69 | 70 | 50,-1d 71 | 72 | wxLEFT 73 | 10 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | wxEXPAND 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | wxEXPAND 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 80,-1d 103 | 104 | 105 | 106 | wxALL 107 | 5 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /modLdap/_requires.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | # Mac OSX 10.8, 10.9: 9 | # xcode-select --install 10 | # sudo easy_install pip 11 | # sudo pip install python-ldap 12 | # 13 | # Debian: 14 | # apt-get install python-ldap 15 | # 16 | # Windows: 17 | # https://pypi.python.org/pypi/python-ldap 18 | # current: 19 | # https://pypi.python.org/packages/2.7/p/python-ldap/python-ldap-2.4.12.win32-py2.7.msi 20 | # alternate: 21 | # http://www.lfd.uci.edu/~gohlke/pythonlibs/ 22 | # 23 | # other OS: 24 | # http://www.python-ldap.org/download.shtml 25 | 26 | def GetPrerequisites(info=False): 27 | try: 28 | import ldap 29 | if ldap.__version__ < "3.1.": 30 | if info: 31 | print ("ldap too old") 32 | return None 33 | import wx 34 | if wx.VERSION < (4,1): 35 | if info: 36 | print ("wxPython too old") 37 | return None 38 | 39 | return "ldap" 40 | except: 41 | if info: 42 | print ("ldap missing") 43 | pass 44 | return None 45 | -------------------------------------------------------------------------------- /modLdap/attribEmpty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/attribEmpty.png -------------------------------------------------------------------------------- /modLdap/attribMay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/attribMay.png -------------------------------------------------------------------------------- /modLdap/attribMust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/attribMust.png -------------------------------------------------------------------------------- /modLdap/attribRDN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/attribRDN.png -------------------------------------------------------------------------------- /modLdap/hints/instrument.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Server %SERVERNAME% is not instrumented 5 | 6 |

Server is not instrumented

7 |

8 | $APPNAME implements some advanced features, which require additional procedures and tables in the 9 | maintenance database to work. These advanced features are: 10 |

    11 |
  • aborting connections on the connection status page 12 |
  • Favorite objects in the browser tree 13 |
  • SQL code Snippets in the SQL query tool 14 |
  • Filter Presets in the data tool 15 |
  • modifying the server configuration for servers older than 9.4 16 |
17 | Favorites, Snippets and Presets are stored in database tables personal to the user you're using to connect, and are 18 | instantly available on every computer you're connecting from using $APPNAME. 19 |

20 | To prepare the server for improved handling through $APPNAME, execute the instrument 21 | context menu on the server object and close the connection. After re-opening the connection, the instrumentation 22 | state will be detected and the advanced features are available. 23 |

24 | Some instrumentation steps might need preparation before $APPNAME can complete them. Most notably, the adminpack contrib module 25 | must be installed on the server before $APPNAME can register the extension successfully. 26 |

27 | Note: The namespace used for configuration storage is configured in Preferences/PostgreSQL. 28 |

29 | 30 | -------------------------------------------------------------------------------- /modLdap/objectClass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modLdap/objectClass.png -------------------------------------------------------------------------------- /modPg/ConnectDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Connect to database 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 14 | 15 | 10 16 | 10 17 | 1 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | wxEXPAND 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | wxEXPAND 41 | 42 | 43 | 44 | wxALL|wxEXPAND 45 | 10 46 | 47 | 48 | 49 | wxHORIZONTAL 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | wxRIGHT 58 | 10 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND 68 | 10 69 | 70 | 71 | 72 | 12,12d 73 | 74 | wxEXPAND 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /modPg/ConnectionPage.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | wxEXPAND|wxGROW 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | wxALIGN_CENTRE_VERTICAL 26 | 50,-1d 27 | 28 | 29 | 30 | 31 | 32 | wxALIGN_CENTRE_VERTICAL 33 | 34 | 35 | wxEXPAND|wxGROW 36 | 37 | 38 | 39 | 40 | 41 | wxRIGHT|wxALIGN_CENTRE_VERTICAL 42 | 43 | 5 44 | 2 45 | 46 | wxTOP|wxBOTTOM|wxALL|wxEXPAND|wxGROW 47 | 10 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /modPg/DEBUG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/DEBUG.png -------------------------------------------------------------------------------- /modPg/Database-conn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Database-conn.png -------------------------------------------------------------------------------- /modPg/Database-noconn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Database-noconn.png -------------------------------------------------------------------------------- /modPg/Database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Database.png -------------------------------------------------------------------------------- /modPg/ERROR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ERROR.png -------------------------------------------------------------------------------- /modPg/FATAL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/FATAL.png -------------------------------------------------------------------------------- /modPg/Favourite.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | import adm 9 | from wh import xlt 10 | from .Schema import Schema 11 | from .Table import Table 12 | from .Sequence import Sequence 13 | from .View import View 14 | from .Function import Function 15 | 16 | class Favourites(adm.Node): 17 | typename=xlt("Favourites") 18 | shortname=xlt("Favourites") 19 | defaultname=xlt("unsorted") 20 | def __init__(self, parentNode): 21 | super(Favourites, self).__init__(parentNode, xlt(Favourites.defaultname)) 22 | 23 | @staticmethod 24 | def GetInstances(parentNode): 25 | if parentNode.GetServer().fav_table: 26 | return [Favourites(parentNode)] 27 | return None 28 | 29 | def DoRefresh(self): 30 | for treename, fil in self.treeitems.items(): 31 | tree=adm.trees[treename] 32 | favitem=fil[0] # tree.Collapse(favitem) 33 | for child in self.childnodes[:]: 34 | itemlist=child.treeitems.get(treename) 35 | if itemlist: 36 | for item in itemlist: 37 | if tree.IsChild(item, favitem): 38 | tree.DeleteItem(item) 39 | self.removeChild(child) 40 | self.properties=[] 41 | 42 | def GetProperties(self): 43 | self.properties=[] 44 | self.PopulateChildren() 45 | for child in self.childnodes: 46 | self.properties.append( (child.name, child.comment, child.GetIcon())) 47 | return self.properties 48 | 49 | 50 | 51 | class Favourite(adm.Node): 52 | typename=xlt("Favourite") 53 | shortname=xlt("Favourite") 54 | 55 | def DoRefresh(self): 56 | for c in self.childnodes: 57 | for treename, itemlist in c.treeitems.items(): 58 | item=itemlist[0] 59 | tree=adm.trees[treename] 60 | itemlist=tree.GetChildItems(item) 61 | 62 | tree.Collapse(item) 63 | for item in itemlist: 64 | tree.DeleteItem(item) 65 | 66 | self.childnodes=[] 67 | self.properties=[] 68 | self.RefreshVolatile(True) 69 | 70 | 71 | @staticmethod 72 | def GetInstances(parentNode): 73 | instances=[] 74 | db=parentNode.parentNode 75 | if db.favourites: 76 | schemaOids=db.GetCursor().ExecuteList("SELECT DISTINCT relnamespace FROM pg_class WHERE oid IN (%s)" % ",".join(map(str, db.favourites))) 77 | coll=db.GetCollection(Schema) 78 | coll.PopulateChildren() 79 | schemanodes=[] 80 | schemaOids=db.GetCursor().ExecuteList("SELECT DISTINCT relnamespace FROM pg_class WHERE oid IN (%s)" % ",".join(map(str, db.favourites))) 81 | for schema in coll.childnodes: 82 | if schema.GetOid() in schemaOids: 83 | schemanodes.append(schema) 84 | schema.PopulateChildren() 85 | 86 | for schema in schemanodes: 87 | tables=schema.GetCollection(Table) 88 | for oid in db.favourites: 89 | t=tables.FindNode(Table, str(oid)) 90 | if t: 91 | instances.append(t) 92 | 93 | for schema in schemanodes: 94 | views=schema.GetCollection(View) 95 | if views: 96 | for oid in db.favourites: 97 | v=views.FindNode(View, str(oid)) 98 | if v: 99 | instances.append(v) 100 | 101 | for schema in schemanodes: 102 | funcs=schema.GetCollection(Function) 103 | if funcs: 104 | for oid in db.favourites: 105 | f=funcs.FindNode(Function, str(oid)) 106 | if f: 107 | instances.append(f) 108 | 109 | for schema in schemanodes: 110 | sequences=schema.GetCollection(Sequence) 111 | if sequences: 112 | for oid in db.favourites: 113 | s=sequences.FindNode(Sequence, str(oid)) 114 | if s: 115 | instances.append(s) 116 | 117 | return instances 118 | 119 | 120 | 121 | nodeinfo= [ 122 | { "class" : Favourites, "parents": ["Database"], "sort": 80, }, 123 | { "class" : Favourite, "parents": ["Favourites"], "sort": 80, } 124 | ] 125 | 126 | class AddFavourite: 127 | name=xlt("Add Favourite") 128 | help=xlt("Make object a favourite") 129 | 130 | @staticmethod 131 | def CheckAvailableOn(node): 132 | return hasattr(node, 'favtype') and node.GetOid() not in node.GetDatabase().favourites and node.GetServer().fav_table 133 | 134 | @staticmethod 135 | def OnExecute(_parentwin, node): 136 | node.GetServer().AddFavourite(node) 137 | favgroup=xlt(Favourites.defaultname) 138 | fav=node.GetDatabase().FindNode(Favourites, favgroup) 139 | if not fav: 140 | fav=Favourites(node.GetDatabase(), favgroup) 141 | node.GetDatabase().appendNode(fav) 142 | 143 | if fav.childnodes and not node in fav.childnodes: 144 | fav.appendChild(node) 145 | return True 146 | 147 | class DelFavourite: 148 | name=xlt("Delete Favourite") 149 | help=xlt("Delete object from favourite list") 150 | 151 | @staticmethod 152 | def CheckAvailableOn(node): 153 | return hasattr(node, 'favtype') and node.GetOid() in node.GetDatabase().favourites and node.GetServer().fav_table 154 | 155 | 156 | @staticmethod 157 | def OnExecute(_parentwin, node): 158 | node.GetServer().DelFavourite(node) 159 | return True 160 | 161 | 162 | 163 | menuinfo = [ 164 | { "class" : AddFavourite, "nodeclasses" : Table, 'sort': 40 }, 165 | { "class" : DelFavourite, "nodeclasses" : Table, 'sort': 40 }, 166 | ] 167 | -------------------------------------------------------------------------------- /modPg/Favourites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Favourites.png -------------------------------------------------------------------------------- /modPg/Function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Function.png -------------------------------------------------------------------------------- /modPg/Function.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | from ._objects import SchemaObject 9 | from ._pgsql import pgQuery 10 | from wh import xlt, YesNo 11 | import logger 12 | 13 | 14 | class Function(SchemaObject): 15 | typename=xlt("Function") 16 | shortname=xlt("Function") 17 | refreshOid="pro.oid" 18 | allGrants='X' 19 | favtype='f' 20 | relkind='P' 21 | 22 | 23 | 24 | @staticmethod 25 | def FindQuery(schemaName, schemaOid, patterns): 26 | sql=pgQuery("pg_proc p") 27 | sql.AddCol("'P' as kind") 28 | sql.AddCol("nspname") 29 | sql.AddCol("proname as name") 30 | sql.AddCol("n.oid as nspoid") 31 | sql.AddCol("p.oid") 32 | sql.AddJoin("pg_namespace n ON n.oid=pronamespace") 33 | SchemaObject.AddFindRestrictions(sql, schemaName, schemaOid, 'proname', patterns) 34 | return sql 35 | 36 | 37 | @staticmethod 38 | def InstancesQuery(parentNode): 39 | sql=pgQuery("pg_proc pro") 40 | sql.AddCol("pro.oid, pg_get_userbyid(proowner) AS owner, proacl as acl, proname as name, pro.*, nspname, ns.oid as nspoid, lanname, description") 41 | if parentNode.GetServer().version >= 8.4: 42 | sql.AddCol("pg_get_function_arguments(pro.oid) as arguments, pg_get_function_result(pro.oid) as result") 43 | sql.AddJoin("pg_language lang ON lang.oid=prolang") 44 | sql.AddLeft("pg_namespace ns ON ns.oid=pronamespace") 45 | sql.AddLeft("pg_description des ON (des.objoid=pro.oid AND des.objsubid=0)") 46 | sql.AddWhere("pronamespace", parentNode.parentNode.GetOid()) 47 | sql.AddOrder("proname") 48 | return sql 49 | 50 | def __init__(self, parentNode, info): 51 | super(Function, self).__init__(parentNode, info) 52 | args=self.info.get('arguments') 53 | if args!= None: 54 | self.name="%s(%s)" % (self.name, args) 55 | 56 | def GetIcon(self): 57 | icons=[] 58 | icons.append("Function") 59 | if self.GetOid() in self.GetDatabase().favourites: 60 | icons.append('fav') 61 | return self.GetImageId(icons) 62 | 63 | 64 | def GetSql(self): 65 | definition=self.info.get('definition') 66 | if not definition: 67 | definition=self.GetCursor().ExecuteSingle("SELECT pg_get_functiondef(%d)" % self.GetOid()) 68 | self.info['definition']=definition[:-1] + ";" 69 | return "%(def)s\n%(grant)s" % { 70 | 'object': self.ObjectSql(), 71 | 'def': definition, 'grant': self.GrantCommentSql() } 72 | 73 | 74 | def GetProperties(self): 75 | if not len(self.properties): 76 | args=self.info.get('arguments') 77 | if args == None: 78 | logger.error("PGSQL < 8.4; no function args/returns") 79 | args="" 80 | self.info['arguments']="" 81 | self.info['result']="" 82 | self.info['definition']=None 83 | result=self.info.get('result', "") 84 | self.properties = [ 85 | (xlt("Name"), "%s(%s)" % (self.info['name'], args)), 86 | (xlt("Namespace"), self.info['nspname']), 87 | (xlt("Language"), self.info['lanname']), 88 | (xlt("Strict"), YesNo(self.info['proisstrict'])), 89 | ( "OID" , self.info['oid']), 90 | (xlt("Returns"), result), 91 | (xlt("Owner"), self.info['owner']), 92 | (xlt("ACL"), self.info['acl']) 93 | ] 94 | 95 | self.AddProperty(xlt("Description"), self.info['description']) 96 | return self.properties 97 | 98 | 99 | nodeinfo= [ { "class" : Function, "parents": ["Schema"], "sort": 60, "collection": "Functions", "pages": ["SqlPage"] } ] 100 | 101 | 102 | -------------------------------------------------------------------------------- /modPg/LOG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/LOG.png -------------------------------------------------------------------------------- /modPg/LoggingPage.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | wxBOTTOM|wxRIGHT|wxEXPAND|wxGROW 10 | 5 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | wxALIGN_CENTRE_VERTICAL 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | wxALIGN_CENTRE_VERTICAL 27 | 50,-1d 28 | 29 | 30 | 31 | 32 | 33 | wxALIGN_CENTRE_VERTICAL 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | wxEXPAND 42 | 43 | 44 | wxEXPAND|wxGROW 45 | 46 | 47 | 48 | 49 | 50 | 51 | wxALIGN_CENTRE_VERTICAL 52 | 53 | 54 | 55 | 56 | 57 | wxRIGHT|wxALIGN_CENTRE_VERTICAL 58 | 59 | 7 60 | 10 61 | 3 62 | 63 | wxEXPAND 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /modPg/LoglineDlg.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Logline 5 | 200,200d 6 | 7 | 8 | wxVERTICAL 9 | 10 | 11 | 12 | wxLEFT|wxRIGHT|wxEXPAND 13 | 10 14 | 150,100d 15 | 16 | 17 | 18 | wxHORIZONTAL 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 100,180d 32 | 1 33 | 34 | 35 | 36 | 37 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 38 | 10 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /modPg/MatView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/MatView.png -------------------------------------------------------------------------------- /modPg/Partition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Partition.png -------------------------------------------------------------------------------- /modPg/PartitionedTable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/PartitionedTable.png -------------------------------------------------------------------------------- /modPg/Preferences.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 5,7d 13 | 14 | wxALIGN_CENTRE_VERTICAL 15 | 16 | 17 | 18 | 80,5d 19 | 80,-1d 20 | 21 | wxGROW 22 | 23 | 24 | 25 | 26 | 5,22d 27 | 28 | wxALIGN_CENTRE_VERTICAL 29 | 30 | 31 | 32 | 80,20d 33 | 80,-1d 34 | 35 | wxGROW 36 | 37 | 5d 38 | 5d 39 | 1 40 | 41 | 42 | wxALL|wxGROW 43 | 5d 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /modPg/PrivilegePanel.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /modPg/Role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Role.png -------------------------------------------------------------------------------- /modPg/Role.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | import adm 9 | from wh import xlt, YesNo, prettyDate 10 | 11 | class Role(adm.Node): 12 | typename=xlt("Role") 13 | shortname=xlt("Role") 14 | 15 | @staticmethod 16 | def GetInstances(parentNode): 17 | instances=[] 18 | rowset=parentNode.GetConnection().GetCursor().ExecuteSet(""" 19 | SELECT rolname as name, *, 20 | (SELECT array_agg(rolname) FROM pg_roles r JOIN pg_auth_members m on r.oid=m.member WHERE m.roleid=u.oid) AS members, 21 | (SELECT array_agg(rolname) FROM pg_roles r JOIN pg_auth_members m on r.oid=m.roleid WHERE m.member=u.oid) AS memberof 22 | FROM pg_roles u ORDER BY rolname""") 23 | if rowset: 24 | for row in rowset: 25 | if not row: 26 | break 27 | instances.append(Role(parentNode, row['name'], row.getDict())) 28 | return instances 29 | 30 | def __init__(self, parentNode, name, info): 31 | super(Role, self).__init__(parentNode, name) 32 | self.info=info 33 | 34 | def GetIcon(self): 35 | icons=[] 36 | if self.info['members']: 37 | icons.append("Group") 38 | else: 39 | icons.append("User") 40 | return self.GetImageId(icons) 41 | 42 | 43 | def GetProperties(self): 44 | if not len(self.properties): 45 | 46 | self.properties = [ 47 | (xlt("Name"), self.name, self.GetImageId('Role')), 48 | ( "OID", self.info['oid']), 49 | (xlt("Can Login"), YesNo(self.info['rolcanlogin'])), 50 | (xlt("Superuser"), YesNo(self.info['rolsuper'])), 51 | (xlt("Catalog Update"), YesNo(self.info['rolcatupdate'])), 52 | (xlt("Create DB"), YesNo(self.info['rolcreatedb'])), 53 | (xlt("Create Role"), YesNo(self.info['rolcreaterole'])), 54 | (xlt("Inherits rights"), YesNo(self.info['rolinherit'])), 55 | ] 56 | until=self.info['rolvaliduntil'] 57 | if not until or until.year == 9999: 58 | until=xlt("never") 59 | else: 60 | until=prettyDate(until) 61 | self.properties.append((xlt("Expires"), until)) 62 | 63 | self.AddChildrenProperty(self.info['memberof'], xlt("Member of"), self.GetImageId("Group")) 64 | self.AddChildrenProperty(self.info['members'], xlt("Members"), self.GetImageId("User")) 65 | self.AddChildrenProperty(self.info['rolconfig'], xlt("Variables"), -1) 66 | 67 | return self.properties 68 | 69 | 70 | class RolesPage(adm.NotebookPage): 71 | name=xlt("Roles") 72 | order=50 73 | availableOn="Server" 74 | roleFlags={'rolcreaterole': 'createRole', 75 | 'rolcreatedb': 'crDb', 76 | 'rolcatupdate': 'catUpd', 77 | 'rolreplication': 'repl' 78 | } 79 | 80 | def Display(self, node, _detached): 81 | if node != self.lastNode: 82 | self.lastNode=node 83 | 84 | def members(row): 85 | d=row['members'] 86 | if d: return ",".join(d) 87 | def flags(row): 88 | fl=[] 89 | for key, desc in self.roleFlags.items(): 90 | if row.get(key): 91 | fl.append(desc) 92 | return" ".join(fl) 93 | 94 | add=self.control.AddColumnInfo 95 | add(xlt("Name"), 20, colname='name') 96 | add(xlt("Flags"), 25, proc=flags) 97 | add(xlt("Members"), 40, proc=members) 98 | 99 | values=[] 100 | 101 | self.allRoles=node.GetConnection().GetCursor().ExecuteDictList(""" 102 | SELECT rolname as name, *, 103 | (SELECT array_agg(rolname) FROM pg_roles r JOIN pg_auth_members m on r.oid=m.member WHERE m.roleid=u.oid) AS members, 104 | (SELECT array_agg(rolname) FROM pg_roles r JOIN pg_auth_members m on r.oid=m.roleid WHERE m.member=u.oid) AS memberof 105 | FROM pg_roles u ORDER BY rolname""") 106 | 107 | for role in self.allRoles: 108 | # rolsuper, rolcreaterole, colcreatedb, rolcanupdate 109 | icons=[] 110 | if role['members']: 111 | icons.append("group") 112 | elif role['rolsuper']: 113 | icons.append('admin') 114 | else: 115 | icons.append("user") 116 | if role['rolcanlogin']: 117 | icons.append('key') 118 | 119 | icon=self.lastNode.GetImageId(icons) 120 | values.append( (role, icon)) 121 | self.control.Fill(values, 'name') 122 | 123 | pageinfo=[RolesPage] 124 | nodeinfo=[] 125 | #nodeinfo= [ { "class" : Role, "parents": ["Server"], "sort": 70, "collection": xlt("Roles") } ] -------------------------------------------------------------------------------- /modPg/Roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Roles.png -------------------------------------------------------------------------------- /modPg/Schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Schema.png -------------------------------------------------------------------------------- /modPg/Schema.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | from ._objects import DatabaseObject 9 | from ._pgsql import pgQuery 10 | from wh import xlt 11 | 12 | 13 | class Schema(DatabaseObject): 14 | typename=xlt("Schema") 15 | shortname=xlt("Schema") 16 | refreshOid="nsp.oid" 17 | 18 | sysNamespaces=['pg_toast', 'pg_catalog', 'information_schema'] 19 | 20 | @staticmethod 21 | def InstancesQuery(parentNode): 22 | sql=pgQuery("pg_namespace nsp") 23 | sql.AddCol("nsp.oid, nspacl, nspname as name, pg_get_userbyid(nspowner) AS owner, description") 24 | sql.AddLeft("pg_description des ON des.objoid=nsp.oid") 25 | sql.AddWhere("nspname not in (%s)" % ",".join(map(lambda x: "'%s'" % x, Schema.sysNamespaces))) 26 | sql.AddOrder("nspname") 27 | return sql 28 | 29 | 30 | def GetIcon(self): 31 | icons=[] 32 | icons.append("Schema") 33 | if self.name in self.sysNamespaces: 34 | icons.append('pg') 35 | return self.GetImageId(icons) 36 | 37 | def GetSchemaOid(self): 38 | return self.GetOid() 39 | 40 | 41 | def GetProperties(self): 42 | if not len(self.properties): 43 | 44 | self.properties = [ 45 | (xlt("Name"), self.name), 46 | ( "OID" , self.info['oid']), 47 | (xlt("Owner"), self.info['owner']), 48 | (xlt("ACL"), self.info['nspacl']) 49 | ] 50 | 51 | self.AddProperty(xlt("Description"), self.info['description']) 52 | return self.properties 53 | 54 | 55 | nodeinfo= [ { "class" : Schema, "parents": ["Database"], "sort": 4, "collection": xlt("Schemas"), } ] 56 | -------------------------------------------------------------------------------- /modPg/Sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Sequence.png -------------------------------------------------------------------------------- /modPg/Sequence.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | from ._objects import SchemaObject 8 | from ._pgsql import pgQuery 9 | from wh import xlt 10 | import adm 11 | 12 | 13 | 14 | class Sequence(SchemaObject): 15 | typename=xlt("Sequence") 16 | shortname=xlt("Sequence") 17 | refreshOid="rel.oid" 18 | allGrants="rwU" 19 | favtype='s' 20 | relkind='S' 21 | 22 | @staticmethod 23 | def FindQuery(schemaName, schemaOid, patterns): 24 | sql=pgQuery("pg_class c") 25 | sql.AddCol("relkind as kind") 26 | sql.AddCol("nspname") 27 | sql.AddCol("relname as name") 28 | sql.AddCol("n.oid as nspoid") 29 | sql.AddCol("c.oid") 30 | sql.AddJoin("pg_namespace n ON n.oid=relnamespace") 31 | sql.AddWhere("relkind='S'") 32 | SchemaObject.AddFindRestrictions(sql, schemaName, schemaOid, 'relname', patterns) 33 | return sql 34 | 35 | 36 | def GetSql(self): 37 | if not self.properties: 38 | self.GetProperties() 39 | return """CREATE SEQUENCE %(name)s 40 | MINVALUE %(min)d MAXVALUE %(max)d INCREMENT %(inc)d 41 | CACHE %(cache)d START %(start)d; 42 | 43 | %(grant)s""" % { 44 | 'name': self.NameSql(), 45 | 'tablespace': self.TablespaceSql(), 46 | 'min': self.info['min_value'], 47 | 'max': self.info['max_value'], 48 | 'inc': self.info['increment_by'], 49 | 'cache': self.info['cache_value'], 50 | 'start': self.nextval, 51 | 'grant': self.GrantCommentSql() } 52 | 53 | def GetIcon(self): 54 | icons=[] 55 | icons.append("Sequence") 56 | if self.GetOid() in self.GetDatabase().favourites: 57 | icons.append('fav') 58 | return self.GetImageId(icons) 59 | 60 | 61 | @staticmethod 62 | def InstancesQuery(parentNode): 63 | sql=pgQuery("pg_class rel") 64 | sql.AddCol("rel.oid, relname as name, nspname, ns.oid as nspoid, spcname, pg_get_userbyid(relowner) AS owner, relacl as acl, relkind") 65 | sql.AddCol("description") 66 | sql.AddJoin("pg_namespace ns ON ns.oid=rel.relnamespace") 67 | sql.AddLeft("pg_tablespace ta ON ta.oid=rel.reltablespace") 68 | sql.AddLeft("pg_description des ON (des.objoid=rel.oid AND des.objsubid=0)") 69 | sql.AddWhere("relkind in ('S')") 70 | sql.AddWhere("relnamespace", parentNode.parentNode.GetOid()) 71 | sql.AddOrder("CASE WHEN nspname='%s' THEN ' ' else nspname END" % "public") 72 | sql.AddOrder("relname") 73 | if parentNode.GetServer().version >= 10: 74 | sql.AddJoin("pg_sequence seq ON seqrelid=rel.oid") 75 | sql.AddCol("seqincrement AS increment_by, seqstart AS start_value") 76 | sql.AddCol("seqmin AS min_value, seqmax AS max_value, seqcache AS cache_value") 77 | sql.AddCol("seqcycle AS is_cycled") 78 | return sql 79 | 80 | def GetProperties(self): 81 | if not len(self.properties): 82 | row=self.GetCursor().ExecuteRow("SELECT * FROM %s" % self.NameSql()) 83 | self.info.update(row.getDict()) 84 | self.nextval=self.info['last_value'] 85 | if self.info['is_called']: 86 | self.nextval += self.info['increment_by'] 87 | 88 | self.properties = [ 89 | (xlt("Name"), self.info['name']), 90 | (xlt("Namespace"), self.info['nspname']), 91 | ( "OID" , self.info['oid']), 92 | (xlt("Owner"), self.info['owner']), 93 | (xlt("Tablespace"), self.info['spcname']), 94 | (xlt("ACL"), self.info['acl']), 95 | (xlt("Next Value"), self.nextval), 96 | (xlt("Increment"), self.info['increment_by']), 97 | (xlt("Min Value"), self.info['min_value']), 98 | (xlt("Max Value"), self.info['max_value']), 99 | (xlt("Cache"), self.info['cache_value']), 100 | (xlt("Cycled"), self.info['is_cycled']) 101 | ] 102 | 103 | self.AddProperty(xlt("Description"), self.info['description']) 104 | 105 | return self.properties 106 | 107 | 108 | class Dlg(adm.PropertyDialog): 109 | 110 | def Go(self): 111 | pass 112 | 113 | def Check(self): 114 | ok=True 115 | if not self.node: 116 | pass 117 | 118 | return ok 119 | 120 | 121 | nodeinfo= [ { "class" : Sequence, "parents": ["Schema"], "sort": 70, "collection": "Sequences", "pages": ["SqlPage"] } ] 122 | -------------------------------------------------------------------------------- /modPg/Sequence.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 2 9 | 10 | 11 | 12 | 5,7d 13 | 14 | 15 | 16 | 17 | 50,5d 18 | 80,-1d 19 | 20 | 21 | 22 | 23 | 24 | 5,22d 25 | 26 | 27 | 28 | 29 | 50,20d 30 | 80,-1d 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 80,-1d 41 | 42 | 43 | 44 | 45 | 46 | 5,37d 47 | 48 | 49 | 50 | 51 | 50,37d 52 | 53 | 54 | 55 | 56 | 57 | 5,52d 58 | 59 | 60 | 61 | 62 | 50,50d 63 | 35,-1d 64 | 65 | 66 | 67 | 68 | 69 | 5,82d 70 | 71 | 72 | 73 | 74 | 50,80d 75 | 80,-1d 76 | 77 | 78 | 10 79 | 10 80 | 81 | wxALL 82 | 10 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /modPg/Server.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Server.ico -------------------------------------------------------------------------------- /modPg/Server.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PostgreSQL Server 5 | 6 | wxVERTICAL 7 | 8 | 9 | 2 10 | 11 | 12 | 13 | 5,7d 14 | 15 | 16 | 17 | 18 | 50,5d 19 | 80,-1d 20 | 21 | 22 | 23 | 24 | 25 | 5,22d 26 | 27 | 28 | 29 | 30 | 50,20d 31 | 80,-1d 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | postgres 42 | 80,-1d 43 | 44 | 45 | 46 | 47 | 48 | 5,37d 49 | 50 | 51 | 52 | 53 | 50,37d 54 | 55 | 56 | 57 | 58 | 59 | 5,52d 60 | 61 | 62 | 63 | 64 | 50,50d 65 | 5432 66 | 35,-1d 67 | 68 | 69 | 70 | 71 | 72 | 5,82d 73 | 74 | 75 | 76 | 77 | 50,80d 78 | postgres 79 | 80,-1d 80 | 81 | 82 | 83 | 84 | 85 | 5,97d 86 | 87 | 88 | 89 | 90 | 50,95d 91 | 80,-1d 92 | 93 | 94 | 95 | 96 | 97 | 5,112d 98 | 99 | 100 | 101 | 102 | 103 | 1 104 | 50,112d 105 | 106 | 107 | 10 108 | 10 109 | 110 | wxALL 111 | 10 112 | 113 | 114 | 115 | wxHORIZONTAL 116 | 117 | 118 | wxEXPAND 119 | 120 | 121 | 122 | 123 | 40,130d 124 | 45,-1d 125 | 126 | wxRIGHT 127 | 10 128 | 129 | 130 | 131 | 132 | 95,130d 133 | 45,-1d 134 | 135 | 136 | 137 | 138 | wxTOP|wxBOTTOM|wxRIGHT|wxEXPAND 139 | 10 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /modPg/ServerSetting.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Server settings 5 | 6 | 7 | wxVERTICAL 8 | 9 | 10 | 2 11 | 12 | 13 | 14 | 15 | wxALIGN_CENTRE_VERTICAL 16 | 17 | 18 | 19 | 20 | 21 | 22 | 5 23 | 10 24 | 1 25 | 26 | 27 | 28 | 29 | wxALIGN_CENTRE_VERTICAL 30 | 31 | 32 | 33 | wxHORIZONTAL 34 | 35 | 36 | 50,12d 37 | 38 | 39 | wxEXPAND 40 | 50,12d 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | wxLEFT|wxALIGN_CENTRE_VERTICAL 50 | 10 51 | 52 | 53 | 54 | wxTOP|wxBOTTOM|wxEXPAND 55 | 5 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | wxBOTTOM 72 | 5 73 | 74 | 75 | 76 | 77 | 78 | wxBOTTOM 79 | 5 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | wxBOTTOM 97 | 10 98 | 99 | 100 | 0,0 101 | 102 | 103 | 0,0 104 | 105 | 106 | 107 | wxTOP|wxLEFT|wxRIGHT|wxEXPAND 108 | 10 109 | 110 | 111 | 112 | wxHORIZONTAL 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | wxLEFT|wxRIGHT 131 | 10 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | wxTOP|wxBOTTOM|wxLEFT|wxRIGHT|wxGROW 141 | 10 142 | 143 | 144 | 145 | wxEXPAND 146 | 12d 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /modPg/SettingsPage.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | wxVERTICAL 6 | 7 | 8 | 9 | wxBOTTOM|wxRIGHT|wxEXPAND|wxGROW 10 | 5 11 | 12 | 13 | 14 | wxHORIZONTAL 15 | 16 | 17 | 18 | 19 | wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL 20 | 10 21 | 22 | 23 | 24 | 80,-1d 25 | 26 | wxALIGN_CENTRE 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | wxBOTTOM|wxLEFT|wxRIGHT|wxALIGN_CENTRE_VERTICAL 36 | 5 37 | 38 | 39 | wxGROW 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /modPg/SqlData.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/SqlData.ico -------------------------------------------------------------------------------- /modPg/SqlPanel.xrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /modPg/SqlQuery.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/SqlQuery.ico -------------------------------------------------------------------------------- /modPg/Table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/Table.png -------------------------------------------------------------------------------- /modPg/View.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/View.png -------------------------------------------------------------------------------- /modPg/View.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2025 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | from ._objects import SchemaObject 8 | from ._pgsql import pgQuery 9 | from wh import xlt 10 | 11 | 12 | class View(SchemaObject): 13 | typename=xlt("View") 14 | shortname=xlt("View") 15 | grantTypename='TABLE' 16 | refreshOid="rel.oid" 17 | allGrants='arwdDxt' 18 | favtype='v' 19 | relkind='v' 20 | 21 | @staticmethod 22 | def FindQuery(schemaName, schemaOid, patterns): 23 | sql=pgQuery("pg_class c") 24 | sql.AddCol("relkind as kind") 25 | sql.AddCol("nspname") 26 | sql.AddCol("relname as name") 27 | sql.AddCol("n.oid as nspoid") 28 | sql.AddCol("c.oid") 29 | sql.AddJoin("pg_namespace n ON n.oid=relnamespace") 30 | sql.AddWhere("relkind='v'") 31 | SchemaObject.AddFindRestrictions(sql, schemaName, schemaOid, 'relname', patterns) 32 | return sql 33 | 34 | @staticmethod 35 | def InstancesQuery(parentNode): 36 | sql=pgQuery("pg_class rel") 37 | sql.AddCol("rel.oid, relname as name, nspname, ns.oid as nspoid, spcname, pg_get_userbyid(relowner) AS owner, relacl as acl, relkind") 38 | sql.AddCol("description") 39 | sql.AddJoin("pg_namespace ns ON ns.oid=rel.relnamespace") 40 | sql.AddLeft("pg_tablespace ta ON ta.oid=rel.reltablespace") 41 | sql.AddLeft("pg_description des ON (des.objoid=rel.oid AND des.objsubid=0)") 42 | sql.AddLeft("pg_constraint c ON c.conrelid=rel.oid AND c.contype='p'") 43 | sql.AddWhere("relkind in ('v', 'm')") 44 | sql.AddWhere("relnamespace", parentNode.parentNode.GetOid()) 45 | sql.AddOrder("CASE WHEN nspname='%s' THEN ' ' else nspname END" % "public") 46 | sql.AddOrder("relname") 47 | return sql 48 | 49 | 50 | def TypeSql(self): 51 | if self.IsMaterialized(): 52 | return "MATERIALIZED VIEW" 53 | else: 54 | return "VIEW" 55 | 56 | def GetIcon(self): 57 | icons=[] 58 | if self.IsMaterialized(): 59 | icons.append("MatView") 60 | else: 61 | icons.append("View") 62 | if self.GetOid() in self.GetDatabase().favourites: 63 | icons.append('fav') 64 | return self.GetImageId(icons) 65 | 66 | 67 | def GetSql(self): 68 | definition=self.info.get('definition') 69 | if not definition: 70 | definition=self.GetCursor().ExecuteSingle("SELECT pg_get_viewdef(%d, true)" % self.GetOid()) 71 | self.info['definition']=definition 72 | return "CREATE OR REPLACE %(object)s %(name)s %(tablespace)s AS\n%(def)s\n\n%(grant)s" % { 73 | 'object': self.TypeSql(), 74 | 'name': self.NameSql(), 75 | 'tablespace': self.TablespaceSql(), 76 | 'def': definition, 'grant': self.GrantCommentSql() } 77 | 78 | 79 | def GetProperties(self): 80 | if not len(self.properties): 81 | self.info['definition']=None 82 | self.properties = [ 83 | (xlt("Name"), self.info['name']), 84 | (xlt("Namespace"), self.info['nspname']), 85 | ( "OID" , self.info['oid']), 86 | (xlt("Owner"), self.info['owner']), 87 | (xlt("Tablespace"), self.info['spcname']), 88 | (xlt("ACL"), self.info['acl']) 89 | ] 90 | 91 | if self.IsMaterialized(): 92 | self.AddProperty(xlt("Materialized"), xlt("Yes")) 93 | self.AddProperty(xlt("Description"), self.info['description']) 94 | return self.properties 95 | 96 | def IsMaterialized(self): 97 | return self.info['relkind'] == 'm' 98 | 99 | nodeinfo= [ { "class" : View, "parents": ["Schema"], "sort": 30, "collection": "Views", "pages": ["SqlPage"] } ] 100 | 101 | 102 | -------------------------------------------------------------------------------- /modPg/__init__.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | moduleinfo={ 'name': "PostgreSQL Server", 9 | 'modulename': "PostgreSQL", 10 | 'description': "PostgreSQL database server", 11 | 'version': "17.0", 12 | 'revision': "0.9.1", 13 | 'requiredAdmVersion': "3.0.0", 14 | 'testedAdmVersion': "3.0.0", 15 | 'supports': "PostgreSQL 8.1 ... 17 (pre-9.1 with restrictions)", 16 | 'copyright': "(c) 2013-2025 PSE Consulting Andreas Pflug", 17 | 'credits': "psycopg2 from http://initd.org/psycopg using libpq (http://www.postgresql.org)", 18 | } 19 | 20 | import sys 21 | if not hasattr(sys, 'skipSetupInit'): 22 | import adm 23 | import wx 24 | from wh import xlt, floatToTime 25 | from LoggingDialog import LogPanel 26 | 27 | 28 | class SqlPage: 29 | name="SQL" 30 | order=800 31 | 32 | def __init__(self, notebook): 33 | from ._sqledit import SqlEditor 34 | self.control=SqlEditor(notebook) 35 | self.control.SetMarginWidth(1, 2) 36 | self.notebook=notebook 37 | self.lastNode=None 38 | 39 | def GetControl(self): 40 | return self.control 41 | 42 | def Display(self, node, _detached): 43 | if hasattr(node, "GetSql"): 44 | sql=node.GetSql().strip().replace("\n\r", "\n").replace("\r\n", "\n") 45 | else: 46 | sql=xlt("No SQL query available.") 47 | self.control.SetReadOnly(False) 48 | self.control.SetValue(sql) 49 | self.control.SetReadOnly(True) 50 | self.control.SetSelection(0,0) 51 | 52 | moduleinfo['pages'] = [SqlPage] 53 | 54 | 55 | class Preferences(adm.PreferencePanel): 56 | name="PostgreSQL" 57 | configDefaults={ 'AdminNamespace': "Admin4", 58 | 'SettingCategorySort': "Reporting Query" } 59 | 60 | from . import Server 61 | -------------------------------------------------------------------------------- /modPg/_requires.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | # http://initd.org/psycopg/docs/install.html#installation 9 | 10 | def GetPrerequisites(info=False): 11 | try: 12 | import psycopg2 13 | if psycopg2.__version__ > "2.4": 14 | return "psycopg2 csv" 15 | else: 16 | if info: 17 | print ("psycopg2 too old") 18 | except: 19 | if info: 20 | print ("psycopg2 missing") 21 | pass 22 | return None 23 | 24 | moreFiles=['kwlist.h'] -------------------------------------------------------------------------------- /modPg/_sqledit.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | # http://www.scintilla.org/ 9 | import wx 10 | import wx.stc as stc 11 | from ._pgsql import getSqlKeywords, colKeywords 12 | 13 | 14 | class SqlEditor(stc.StyledTextCtrl): 15 | def __init__(self, parent): 16 | stc.StyledTextCtrl.__init__(self, parent) 17 | self.MarkerDefine(0, stc.STC_MARK_ARROW) 18 | self.MarkerSetBackground(0, wx.Colour(255,0,0)) 19 | self.SetIndent(2) 20 | 21 | pt=parent.GetFont().GetPointSize() 22 | font=wx.Font(pt, wx.TELETYPE, wx.NORMAL, wx.NORMAL) 23 | self.SetFont(font) 24 | for i in range(24): 25 | self.StyleSetFont(i, font) 26 | 27 | # STC_SQL_DEFAULT 28 | # STC_SQL_COMMENT, STC_SQL_COMMENTLINE, STC_SQL_COMMENTDOC - comments 29 | # STC_SQL_WORD, STC_SQL_USER1 STC_SQL_USER2 STC_SQL_USER3 STC_SQL_USER4 - keywordlists 0,4,5,6,7 30 | 31 | # STC_SQL_NUMBER, STC_SQL_CHARACTER, STC_SQL_STRING, STC_SQL_OPERATOR - num, '', "", +-()*/ 32 | # STC_SQL_SQLPLUS, STC_SQL_SQLPLUS_PROMPT, STC_SQL_SQLPLUS_COMMENT 33 | # STC_SQL_COMMENTLINEDOC STC_SQL_COMMENTDOCKEYWORD STC_SQL_COMMENTDOCKEYWORDERROR 34 | # STC_SQL_WORD2 35 | # STC_SQL_QUOTEDIDENTIFIER STC_SQL_IDENTIFIER 36 | 37 | commentColor=wx.Colour(128, 128, 128) 38 | keywordColor=wx.Colour(0, 0, 128) 39 | constColor=wx.Colour(0, 96, 0) 40 | 41 | self.SetLexer(stc.STC_LEX_SQL) 42 | self.StyleSetForeground(stc.STC_SQL_DEFAULT, wx.BLACK) 43 | 44 | self.StyleSetForeground(stc.STC_SQL_WORD, keywordColor) 45 | self.StyleSetBold(stc.STC_SQL_WORD, True) 46 | self.StyleSetBold(stc.STC_SQL_USER1, True) 47 | 48 | self.StyleSetForeground(stc.STC_SQL_COMMENT, commentColor) 49 | self.StyleSetForeground(stc.STC_SQL_COMMENTLINE, commentColor) 50 | self.StyleSetForeground(stc.STC_SQL_COMMENTDOC, commentColor) 51 | 52 | self.StyleSetForeground(stc.STC_SQL_NUMBER, constColor) 53 | self.StyleSetForeground(stc.STC_SQL_CHARACTER, constColor) 54 | 55 | self.SetKeyWords(0, ' '.join(getSqlKeywords())) 56 | self.SetKeyWords(4, ' '.join(colKeywords)) 57 | self.SetScrollWidth(100) 58 | self.SetScrollWidthTracking(True) 59 | 60 | 61 | 62 | def ShowLineNumbers(self, how): 63 | if how: 64 | w,_h=self.GetTextExtent("1234") 65 | self.SetMarginWidth(0, w+8) 66 | else: 67 | self.SetMarginWidth(0, 0) 68 | 69 | def BindProcs(self, changeProc, updateUiProc): 70 | if changeProc: 71 | self.Bind(stc.EVT_STC_CHANGE, changeProc) 72 | if updateUiProc: 73 | self.Bind(stc.EVT_STC_UPDATEUI, updateUiProc) 74 | 75 | def MarkerDelete(self): 76 | self.MarkerDeleteAll(-1) 77 | 78 | 79 | def GetSelectOffset(self): 80 | a,e=self.GetSelection() 81 | if a == e: 82 | return 0 83 | else: 84 | return self.LineFromPosition(a) 85 | 86 | def MarkerSet(self, line): 87 | self.MarkerAdd(line, 0) 88 | 89 | 90 | -------------------------------------------------------------------------------- /modPg/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/admin.png -------------------------------------------------------------------------------- /modPg/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/check.png -------------------------------------------------------------------------------- /modPg/clip_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/clip_copy.png -------------------------------------------------------------------------------- /modPg/clip_cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/clip_cut.png -------------------------------------------------------------------------------- /modPg/clip_paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/clip_paste.png -------------------------------------------------------------------------------- /modPg/column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/column.png -------------------------------------------------------------------------------- /modPg/data_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/data_refresh.png -------------------------------------------------------------------------------- /modPg/data_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/data_save.png -------------------------------------------------------------------------------- /modPg/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/delete.png -------------------------------------------------------------------------------- /modPg/edit_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/edit_clear.png -------------------------------------------------------------------------------- /modPg/edit_find.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/edit_find.png -------------------------------------------------------------------------------- /modPg/edit_redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/edit_redo.png -------------------------------------------------------------------------------- /modPg/edit_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/edit_undo.png -------------------------------------------------------------------------------- /modPg/ex_aggregate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_aggregate.png -------------------------------------------------------------------------------- /modPg/ex_append.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_append.png -------------------------------------------------------------------------------- /modPg/ex_bmp_heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_bmp_heap.png -------------------------------------------------------------------------------- /modPg/ex_bmp_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_bmp_index.png -------------------------------------------------------------------------------- /modPg/ex_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_group.png -------------------------------------------------------------------------------- /modPg/ex_hash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_hash.png -------------------------------------------------------------------------------- /modPg/ex_index_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_index_scan.png -------------------------------------------------------------------------------- /modPg/ex_join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_join.png -------------------------------------------------------------------------------- /modPg/ex_limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_limit.png -------------------------------------------------------------------------------- /modPg/ex_materialize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_materialize.png -------------------------------------------------------------------------------- /modPg/ex_merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_merge.png -------------------------------------------------------------------------------- /modPg/ex_nested.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_nested.png -------------------------------------------------------------------------------- /modPg/ex_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_result.png -------------------------------------------------------------------------------- /modPg/ex_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_scan.png -------------------------------------------------------------------------------- /modPg/ex_seek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_seek.png -------------------------------------------------------------------------------- /modPg/ex_setop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_setop.png -------------------------------------------------------------------------------- /modPg/ex_sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_sort.png -------------------------------------------------------------------------------- /modPg/ex_subplan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_subplan.png -------------------------------------------------------------------------------- /modPg/ex_tid_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_tid_scan.png -------------------------------------------------------------------------------- /modPg/ex_unique.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_unique.png -------------------------------------------------------------------------------- /modPg/ex_unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/ex_unknown.png -------------------------------------------------------------------------------- /modPg/fav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/fav.png -------------------------------------------------------------------------------- /modPg/file_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/file_open.png -------------------------------------------------------------------------------- /modPg/file_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/file_save.png -------------------------------------------------------------------------------- /modPg/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/filter.png -------------------------------------------------------------------------------- /modPg/foreignkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/foreignkey.png -------------------------------------------------------------------------------- /modPg/group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/group.png -------------------------------------------------------------------------------- /modPg/hints/instrument.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Server %SERVERNAME% is not instrumented 5 | 6 |

Server is not instrumented

7 |

8 | $APPNAME implements some advanced features, which require additional procedures and tables in the 9 | maintenance database to work. These advanced features are: 10 |

    11 |
  • aborting connections on the connection status page 12 |
  • Favorite objects in the browser tree 13 |
  • SQL code Snippets in the SQL query tool 14 |
  • Filter Presets in the data tool 15 |
  • modifying the server configuration for servers older than 9.4 16 |
17 | Favorites, Snippets and Presets are stored in database tables personal to the user you're using to connect, and are 18 | instantly available on every computer you're connecting from using $APPNAME. 19 |

20 | To prepare the server for improved handling through $APPNAME, execute the instrument 21 | context menu on the server object and close the connection. After re-opening the connection, the instrumentation 22 | state will be detected and the advanced features are available. 23 |

24 | Some instrumentation steps might need preparation before $APPNAME can complete them. Most notably, the adminpack contrib module 25 | must be installed on the server before $APPNAME can register the extension successfully. 26 |

27 | Note: The namespace used for configuration storage is configured in Preferences/PostgreSQL. 28 |

29 | 30 | -------------------------------------------------------------------------------- /modPg/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/index.png -------------------------------------------------------------------------------- /modPg/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/key.png -------------------------------------------------------------------------------- /modPg/pg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/pg.png -------------------------------------------------------------------------------- /modPg/primarykey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/primarykey.png -------------------------------------------------------------------------------- /modPg/query_cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/query_cancel.png -------------------------------------------------------------------------------- /modPg/query_execfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/query_execfile.png -------------------------------------------------------------------------------- /modPg/query_execute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/query_execute.png -------------------------------------------------------------------------------- /modPg/query_explain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/query_explain.png -------------------------------------------------------------------------------- /modPg/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/setting.png -------------------------------------------------------------------------------- /modPg/settingChanged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/settingChanged.png -------------------------------------------------------------------------------- /modPg/settingInternal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/settingInternal.png -------------------------------------------------------------------------------- /modPg/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/snippet.png -------------------------------------------------------------------------------- /modPg/snippet_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/snippet_add.png -------------------------------------------------------------------------------- /modPg/snippet_replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/snippet_replace.png -------------------------------------------------------------------------------- /modPg/snippets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/snippets.png -------------------------------------------------------------------------------- /modPg/statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/statistics.png -------------------------------------------------------------------------------- /modPg/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/modPg/user.png -------------------------------------------------------------------------------- /new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/new.png -------------------------------------------------------------------------------- /property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/property.png -------------------------------------------------------------------------------- /refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/refresh.png -------------------------------------------------------------------------------- /requirements-mac.txt: -------------------------------------------------------------------------------- 1 | wxPython==4.2.2 2 | dnspython==2.7.0 3 | python-ldap==3.4.4 4 | psycopg2-binary==2.9.10 5 | docker==7.1.0 6 | GitPython==3.1.44 7 | py2app==0.28.8 8 | setuptools==70.3.0 9 | -------------------------------------------------------------------------------- /version.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | import sys 9 | if not hasattr(sys, 'frozen'): 10 | import wx 11 | if wx.VERSION < (4,1,1): 12 | raise Exception("wx Version too old") 13 | try: 14 | from __version import * # @UnusedWildImport 15 | except: 16 | version="3.x-nightly" 17 | modDate=None 18 | revDate=None 19 | tagDate=None 20 | revLocalChange=True 21 | revDirty=True 22 | revOriginChange=True 23 | requiredAdmVersion="3.0" 24 | 25 | 26 | class Version: 27 | def __init__(self, version): 28 | self.version=str(version) 29 | 30 | def str(self): 31 | return self.version 32 | 33 | def __str__(self): 34 | return self.version 35 | 36 | def fullver(self): 37 | ver=[] 38 | if self.version: 39 | for v in self.version.split('.'): 40 | ver.append("%03d" % int(v)) 41 | return ".".join(ver) 42 | 43 | def __lt__(self, cmp): 44 | return self.fullver() < cmp.fullver() 45 | 46 | def __le__(self, cmp): 47 | return self.fullver() <= cmp.fullver() 48 | 49 | def __gt__(self, cmp): 50 | return self.fullver() > cmp.fullver() 51 | 52 | def __ge__(self, cmp): 53 | return self.fullver() >= cmp.fullver() 54 | 55 | def __eq__(self, cmp): 56 | return self.fullver() == cmp.fullver() 57 | 58 | def __ne__(self, cmp): 59 | return self.fullver() != cmp.fullver() 60 | 61 | 62 | 63 | requiredAdmVersion=Version(requiredAdmVersion) 64 | libVersion=Version("3.0.0") 65 | 66 | appName="Admin4" 67 | RELEASE_CHECK_URL="https://api.github.com/repos/andreas-p/admin4/releases" 68 | RELEASE_URL="https://github.com/andreas-p/admin4/releases" 69 | 70 | description="""4th generation Administration Tool 71 | 72 | Help and manual: http://www.admin4.org/docs 73 | Releases: %s""" % RELEASE_URL 74 | vendor="PSE" 75 | vendorDisplay="PSE Consulting" 76 | copyright="(c) 2013-2023 PSE Consulting Andreas Pflug" 77 | license="Apache License V2.0" 78 | author="PSE Consulting Andreas Pflug" 79 | -------------------------------------------------------------------------------- /wxWidgets.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/wxWidgets.ico -------------------------------------------------------------------------------- /xmlhelp.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2022 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | import xml.dom.minidom as minidom 9 | 10 | 11 | class Element(minidom.Element): 12 | def addElement(self, name): 13 | e=self.ownerDocument.createElement(name) 14 | self.appendChild(e) 15 | return e 16 | 17 | def addElementIfText(self, name, val): 18 | if val != None: 19 | return self.addElementText(name, val) 20 | return None 21 | 22 | def addElementText(self, name, val): 23 | t=minidom.Text() 24 | if val: 25 | t.data=str(val) 26 | else: 27 | t.data="" 28 | t.ownerDocument=self.ownerDocument 29 | 30 | e=self.addElement(name) 31 | e.appendChild(t) 32 | return e 33 | 34 | def addElementTree(self, el): 35 | if isinstance(el, str): 36 | doc=minidom.parseString(el) 37 | el=doc.documentElement 38 | e=self.ownerDocument.importNode(el, True) 39 | self.appendChild(e) 40 | return e 41 | 42 | def setAttribute(self, name, val): 43 | minidom.Element.setAttribute(self, name, val) 44 | return self 45 | 46 | def setAttributes(self, attribs): 47 | for key, val in attribs.items(): 48 | self.setAttribute(key, str(val)) 49 | return self 50 | 51 | def getText(self): 52 | pt=[] 53 | for node in self.childNodes: 54 | if node.nodeType == node.TEXT_NODE: 55 | pt.append(node.data) 56 | return "".join(pt) 57 | 58 | def getElements(self, name): 59 | return self.getElementsByTagName(name) 60 | 61 | def getElement(self, name): 62 | es=self.getElementsByTagName(name) 63 | if es: 64 | return es[0] 65 | return None 66 | 67 | def getElementText(self, name, default=None): 68 | n=self.getElement(name) 69 | if n: 70 | return n.getText() 71 | return default 72 | 73 | def prettyXml(self): 74 | lines=self.toprettyxml().splitlines(1) 75 | out=[] 76 | for line in lines: 77 | if line.strip(): 78 | out.append(line) 79 | return "".join(out) 80 | 81 | 82 | 83 | class DOMImplementation(minidom.DOMImplementation): 84 | def _create_document(self): 85 | return Document() 86 | 87 | class Document(minidom.Document): 88 | implementation=DOMImplementation() 89 | 90 | @staticmethod 91 | def create(rootName): 92 | doc=Document.implementation.createDocument(None, rootName, None) 93 | return doc.documentElement 94 | 95 | @staticmethod 96 | def parseRaw(txt): 97 | doc=minidom.parseString(txt) 98 | return doc.documentElement 99 | 100 | @staticmethod 101 | def parse(txt): 102 | doc=Document.implementation.createDocument(None, "none", None) 103 | rootRaw=Document.parseRaw(txt) 104 | root=doc.importNode(rootRaw, True) 105 | doc.rootElement=root 106 | return root 107 | 108 | @staticmethod 109 | def parseFile(filename): 110 | doc=Document.implementation.createDocument(None, "none", None) 111 | raw=minidom.parse(filename) 112 | root=doc.importNode(raw.documentElement, True) 113 | doc.rootElement=root 114 | return root 115 | 116 | def createElement(self, tagName): 117 | e=Element(tagName) 118 | e.ownerDocument=self 119 | return e 120 | 121 | def createElementNS(self, namespaceURI, qualifiedName): 122 | prefix, _localName = minidom._nssplit(qualifiedName) 123 | e = Element(qualifiedName, namespaceURI, prefix) 124 | e.ownerDocument = self 125 | return e 126 | -------------------------------------------------------------------------------- /xmlres.py: -------------------------------------------------------------------------------- 1 | # The Admin4 Project 2 | # (c) 2013-2025 Andreas Pflug 3 | # 4 | # Licensed under the Apache License, 5 | # see LICENSE.TXT for conditions of usage 6 | 7 | 8 | import wx.xrc as xrc 9 | import os, importlib 10 | 11 | xmlControlList={} 12 | 13 | def init(loaddir): 14 | names=os.listdir(loaddir) 15 | found=[] 16 | for name in names: 17 | path="%s/%s" % (loaddir, name) 18 | if os.path.isdir(path): 19 | pass 20 | # do not scan for CTL sources everywhere 21 | # If necessary, restrict to modXXX 22 | #init(path) 23 | elif name.startswith("ctl_") and name.endswith( (".py", ".pyc")): 24 | name=name[:name.rfind('.')] 25 | if name not in found: 26 | found.append(name) 27 | mod=importlib.import_module(name, loaddir) 28 | xmlControlList.update(mod.xmlControlList) 29 | 30 | 31 | def getControlClass(name): 32 | return xmlControlList.get(name) 33 | 34 | class XmlResourceHandler(xrc.XmlResourceHandler): 35 | def DoCreateResource(self): 36 | cls=xmlControlList.get(self.GetClass()) 37 | ctl=None 38 | if cls: 39 | # self.AddStyle("whEXTRAStyle", 4711) 40 | ctl=cls(self.GetParentAsWindow(), cid=self.GetID(), pos=self.GetPosition(), size=self.GetSize(), style=self.GetStyle()) 41 | self.SetupWindow(ctl) 42 | return ctl 43 | 44 | def CanHandle(self, node): 45 | return node.GetAttribute('class', "") in xmlControlList 46 | 47 | -------------------------------------------------------------------------------- /xrced/XRCed_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/xrced/XRCed_16.png -------------------------------------------------------------------------------- /xrced/XRCed_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/xrced/XRCed_32.png -------------------------------------------------------------------------------- /xrced/encode_bitmaps.py: -------------------------------------------------------------------------------- 1 | """ 2 | A simple script to encode all the images the XRCed needs into a Python module 3 | """ 4 | 5 | import sys, os, glob 6 | from wx.tools import img2py 7 | 8 | def main(): 9 | output = 'images.py' 10 | 11 | # get the list of PNG files 12 | files = glob.glob('src-images/*.png') 13 | files.sort() 14 | 15 | # Truncate the inages module 16 | open(output, 'w') 17 | 18 | # call img2py on each file 19 | for file in files: 20 | 21 | # extract the basename to be used as the image name 22 | name = os.path.splitext(os.path.basename(file))[0] 23 | 24 | # encode it 25 | if file == files[0]: 26 | cmd = "-u -i -n %s %s %s" % (name, file, output) 27 | else: 28 | cmd = "-a -u -i -n %s %s %s" % (name, file, output) 29 | img2py.main(cmd.split()) 30 | 31 | 32 | if __name__ == "__main__": 33 | main() 34 | 35 | -------------------------------------------------------------------------------- /xrced/globals.py: -------------------------------------------------------------------------------- 1 | # Name: globals.py 2 | # Purpose: XRC editor, global variables 3 | # Author: Roman Rolinsky 4 | # Created: 02.12.2002 5 | # RCS-ID: $Id: globals.py,v 1.31 2007/03/08 15:49:34 ROL Exp $ 6 | 7 | import wx 8 | 9 | 10 | # Global constants 11 | progname = 'XRCed' 12 | version = '0.1.8-4-admin4' 13 | # Minimal wxWidgets version 14 | MinWxVersion = (2,6,0) 15 | if wx.VERSION[:3] < MinWxVersion: 16 | print ('''\ 17 | ******************************* WARNING ************************************** 18 | This version of XRCed may not work correctly on your version of wxWidgets. 19 | Please upgrade wxWidgets to %d.%d.%d or higher. 20 | ******************************************************************************''' % MinWxVersion) 21 | 22 | 23 | 24 | # Global variables 25 | 26 | class Globals: 27 | panel = None 28 | tree = None 29 | frame = None 30 | tools = None 31 | undoMan = None 32 | testWin = None 33 | testWinPos = wx.DefaultPosition 34 | currentXXX = None 35 | 36 | def _makeFonts(self): 37 | self._sysFont = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT) 38 | self._labelFont = wx.Font(self._sysFont.GetPointSize(), wx.DEFAULT, wx.NORMAL, wx.BOLD) 39 | self._modernFont = wx.Font(self._sysFont.GetPointSize(), wx.MODERN, wx.NORMAL, wx.NORMAL) 40 | self._smallerFont = wx.Font(self._sysFont.GetPointSize()-2, wx.DEFAULT, wx.NORMAL, wx.NORMAL) 41 | 42 | def sysFont(self): 43 | if not hasattr(self, "_sysFont"): self._makeFonts() 44 | return self._sysFont 45 | def labelFont(self): 46 | if not hasattr(self, "_labelFont"): self._makeFonts() 47 | return self._labelFont 48 | def modernFont(self): 49 | if not hasattr(self, "_modernFont"): self._makeFonts() 50 | return self._modernFont 51 | def smallerFont(self): 52 | if not hasattr(self, "_smallerFont"): self._makeFonts() 53 | return self._smallerFont 54 | 55 | 56 | g = Globals() 57 | -------------------------------------------------------------------------------- /xrced/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002, Roman Rolinsky 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /xrced/xrced.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas-p/admin4/129afc9f39daa2f9f16a2ef5d1c10341f7f4e9a3/xrced/xrced.ico --------------------------------------------------------------------------------