├── Core ├── __init__.py ├── SharedApp.py ├── ProjectRepository.py ├── CustomException.py ├── DatabaseLockHandler.py ├── Debugger.py └── EmailNotification.py ├── GUI ├── __init__.py ├── GUILibraries.py ├── NotificationGUI.py ├── ChangeNameGUI.py ├── ApplyFiltersGUI.py ├── PathChangeGUI.py ├── AboutFixityGUI.py ├── ImportProjGUI.py ├── ChangeAlgorithmGUI.py └── EmailNotificationGUI.py ├── tests ├── AllFixture │ ├── __init__.py │ ├── helper.py │ ├── EmailFixtures.py │ ├── RequiredsCreationFixture.py │ ├── ProjectFixtures.py │ ├── AlgorithmFixtures.py │ └── Fixtures.py ├── __init__.py ├── TestCases │ ├── __init__.py │ ├── ExpectedResults.py │ ├── EmailTestCase.py │ ├── FailedMessages.py │ ├── RequiredsCreationTestCase.py │ └── ProjectTestCase.py ├── .coverage ├── assets │ ├── icon.ico │ ├── avpreserve.png │ ├── logo_sign_small.png │ ├── logo_sign_trans.icns │ └── template │ │ ├── History.txt │ │ ├── ReportEmail.txt │ │ ├── Report.txt │ │ ├── SchedulerMacDaily.xml │ │ ├── SchedulerMacMonth.xml │ │ ├── SchedulerMacWeek.xml │ │ ├── SchedulerWinDaily.xml │ │ ├── SchedulerWinWeek.xml │ │ └── SchedulerWinMonth.xml ├── generate_report.py ├── documentation.md └── TestSuite.py ├── test.py ├── assets ├── Thumbs.db ├── icon.ico ├── avpreserve.png ├── logo_sign_small.png ├── logo_sign_trans.icns └── template │ ├── History.txt │ ├── ReportEmail.txt │ ├── Report.txt │ ├── SchedulerMacDaily.xml │ ├── SchedulerMacMonth.xml │ ├── SchedulerMacWeek.xml │ ├── SchedulerWinDaily.xml │ ├── SchedulerWinWeek.xml │ ├── SchedulerWinDailyAdmin.xml │ ├── SchedulerWinWeekAdmin.xml │ ├── SchedulerWinMonth.xml │ └── SchedulerWinMonthAdmin.xml ├── .stickler.yml ├── Config ├── __init__.py ├── Validation.py ├── Setup.py └── Configuration.py ├── .eggs └── README.txt ├── setup.py ├── .gitignore ├── setup.spec ├── Main.spec ├── App.py ├── fileVerificationMethod.md ├── Main.py └── readme.md /Core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /GUI/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/AllFixture/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | __author__ = 'furqanwasi' 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Furqan' 2 | -------------------------------------------------------------------------------- /tests/TestCases/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Furqan' 2 | -------------------------------------------------------------------------------- /assets/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/assets/Thumbs.db -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/assets/icon.ico -------------------------------------------------------------------------------- /tests/.coverage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/tests/.coverage -------------------------------------------------------------------------------- /.stickler.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | flake8: 3 | fixer: true 4 | fixers: 5 | enable: true 6 | -------------------------------------------------------------------------------- /assets/avpreserve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/assets/avpreserve.png -------------------------------------------------------------------------------- /tests/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/tests/assets/icon.ico -------------------------------------------------------------------------------- /Config/__init__.py: -------------------------------------------------------------------------------- 1 | from Config import Configuration 2 | Configuration = Configuration.Configuration -------------------------------------------------------------------------------- /assets/logo_sign_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/assets/logo_sign_small.png -------------------------------------------------------------------------------- /assets/logo_sign_trans.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/assets/logo_sign_trans.icns -------------------------------------------------------------------------------- /tests/assets/avpreserve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/tests/assets/avpreserve.png -------------------------------------------------------------------------------- /tests/assets/logo_sign_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/tests/assets/logo_sign_small.png -------------------------------------------------------------------------------- /tests/assets/logo_sign_trans.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeAreAVP/fixity/HEAD/tests/assets/logo_sign_trans.icns -------------------------------------------------------------------------------- /assets/template/History.txt: -------------------------------------------------------------------------------- 1 | {{base_directory}} 2 | {{email_address}} 3 | {{schedule}} 4 | {{last_ran}} 5 | {{filters}} 6 | {{algo}} 7 | {{content}} -------------------------------------------------------------------------------- /tests/assets/template/History.txt: -------------------------------------------------------------------------------- 1 | {{base_directory}} 2 | {{email_address}} 3 | {{schedule}} 4 | {{last_ran}} 5 | {{filters}} 6 | {{algo}} 7 | {{content}} -------------------------------------------------------------------------------- /Core/SharedApp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | 7 | ''' 8 | 9 | class SharedApp(object): 10 | App = None 11 | 12 | -------------------------------------------------------------------------------- /.eggs/README.txt: -------------------------------------------------------------------------------- 1 | This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins. 2 | 3 | This directory caches those eggs to prevent repeated downloads. 4 | 5 | However, it is safe to delete this directory. 6 | 7 | -------------------------------------------------------------------------------- /tests/AllFixture/helper.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def setImportBaseBath(): 4 | base_path = os.getcwd() 5 | base_path = base_path.replace(r'\tests', '') 6 | base_path = base_path.replace(r'\AllFixture', '') 7 | base_path = base_path.replace(r'/tests', '') 8 | base_path = base_path.replace(r'/AllFixture', '') 9 | return os.path.join(base_path,'') -------------------------------------------------------------------------------- /assets/template/ReportEmail.txt: -------------------------------------------------------------------------------- 1 | Fixity report 2 | Project name {{project_name}} 3 | Algorithm used {{algo}} 4 | Date {{date}} 5 | Time Elapsed {{time_elapsed}} 6 | Total Files {{total_files}} 7 | Confirmed Files {{confirmed_files}} 8 | Moved or Renamed Files {{moved_or_renamed_files}} 9 | New Files {{new_files}} 10 | Changed Files {{changed_files}} 11 | Removed Files {{removed_files}} -------------------------------------------------------------------------------- /assets/template/Report.txt: -------------------------------------------------------------------------------- 1 | Fixity report 2 | Project name {{project_name}} 3 | Algorithm used {{algo}} 4 | Date {{date}} 5 | Time Elapsed {{time_elapsed}} 6 | Total Files {{total_files}} 7 | Confirmed Files {{confirmed_files}} 8 | Moved or Renamed Files {{moved_or_renamed_files}} 9 | New Files {{new_files}} 10 | Changed Files {{changed_files}} 11 | Removed Files {{removed_files}} 12 | {{details}} -------------------------------------------------------------------------------- /tests/assets/template/ReportEmail.txt: -------------------------------------------------------------------------------- 1 | Fixity report 2 | Project name {{project_name}} 3 | Algorithm used {{algo}} 4 | Date {{date}} 5 | Time Elapsed {{time_elapsed}} 6 | Total Files {{total_files}} 7 | Confirmed Files {{confirmed_files}} 8 | Moved or Renamed Files {{moved_or_renamed_files}} 9 | New Files {{new_files}} 10 | Changed Files {{changed_files}} 11 | Removed Files {{removed_files}} -------------------------------------------------------------------------------- /GUI/GUILibraries.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | 7 | ''' 8 | 9 | ''' Built-in Libraries ''' 10 | from PySide.QtCore import * 11 | from PySide.QtGui import * 12 | 13 | import os 14 | import re 15 | 16 | #custome Library 17 | from messages import messages 18 | from GUI import NotificationGUI 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/assets/template/Report.txt: -------------------------------------------------------------------------------- 1 | Fixity report 2 | Project name {{project_name}} 3 | Algorithm used {{algo}} 4 | Date {{date}} 5 | Time Elapsed {{time_elapsed}} 6 | Total Files {{total_files}} 7 | Confirmed Files {{confirmed_files}} 8 | Moved or Renamed Files {{moved_or_renamed_files}} 9 | New Files {{new_files}} 10 | Changed Files {{changed_files}} 11 | Removed Files {{removed_files}} 12 | {{details}} -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a setup.py script generated by py2applet 3 | 4 | Usage: 5 | python setup.py py2app 6 | """ 7 | 8 | from setuptools import setup 9 | 10 | APP = ['Main.py'] 11 | DATA_FILES = [] 12 | OPTIONS = {'argv_emulation': True, 'includes': ['sip', 'PySide.QtCore','PySide.QtGui', 'Crypto'], 'iconfile':'assets/logo_sign_trans.icns','resources':'assets'} 13 | setup( 14 | app=APP, 15 | name='Fixity', 16 | data_files=DATA_FILES, 17 | options={'py2app': OPTIONS}, 18 | setup_requires=['py2app'] 19 | ) 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .pydevproject 3 | .settings 4 | *.pyc 5 | *.tsv 6 | *.conf 7 | conf.xml 8 | *.sch 9 | *.bat 10 | *.vb 11 | .dblocker.log.lock.swp 12 | dblocker.log 13 | .project 14 | .pyproject 15 | .DS_Store 16 | Fixity.db 17 | debug.log 18 | conf.xml 19 | .settings 20 | .settings/* 21 | .idea 22 | .idea/* 23 | history 24 | history/* 25 | reports 26 | reports/* 27 | bin 28 | schedules/* 29 | bin/* 30 | debug 31 | debug/* 32 | scheduler 33 | scheduler/* 34 | __pycache__ 35 | __pycache__/* 36 | build 37 | build/* 38 | dist/* 39 | dist 40 | -------------------------------------------------------------------------------- /setup.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | a = Analysis(['setup.py'], 3 | pathex=['c:\\Users\\wasi\\server\\fixity'], 4 | hiddenimports=[], 5 | hookspath=None) 6 | pyz = PYZ(a.pure) 7 | exe = EXE(pyz, 8 | a.scripts, 9 | exclude_binaries=1, 10 | name=os.path.join('build\\pyi.win32\\setup', 'setup.exe'), 11 | debug=False, 12 | strip=None, 13 | upx=True, 14 | console=True ) 15 | coll = COLLECT(exe, 16 | a.binaries, 17 | a.zipfiles, 18 | a.datas, 19 | strip=None, 20 | upx=True, 21 | name=os.path.join('dist', 'setup')) 22 | -------------------------------------------------------------------------------- /Main.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | a = Analysis(['Main.py'], 3 | pathex=['C:\\PyInstaller\\pyinstaller.py'], 4 | hiddenimports=[], 5 | hookspath=None) 6 | 7 | 8 | a.datas += [('assets\\logo_sign_small.png', 'assets\\logo_sign_small.png','DATA')] 9 | 10 | pyz = PYZ(a.pure) 11 | exe = EXE(pyz, 12 | a.scripts, 13 | a.binaries, 14 | a.zipfiles, 15 | a.datas, 16 | name=os.path.join('dist', 'Fixity.exe'), 17 | debug=False, 18 | strip=None, 19 | upx=True, 20 | console=False , icon='assets\\icon.ico') 21 | app = BUNDLE(exe, 22 | name=os.path.join('dist', 'Fixity.exe.app')) 23 | -------------------------------------------------------------------------------- /Config/Validation.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | #Created on May 14, 2014 3 | # 4 | #@author: Furqan Wasi 5 | import re 6 | __author__ = 'Furqan' 7 | ''' 8 | Validate given email address 9 | @param Email: Email Address 10 | 11 | @return: String Message of failure 12 | ''' 13 | def ValidateProjectName(projectName): 14 | if not re.match(r"^[a-zA-Z0-9-_]+$", projectName): 15 | return False 16 | return True 17 | 18 | ''' Validate given email address 19 | @param Email: Email Address 20 | @return: String Message of failure 21 | 22 | ''' 23 | def ValidateEmail(Email): 24 | if not re.match(r"[^@]+@[^@]+\.[^@]+", Email): 25 | return False 26 | return True -------------------------------------------------------------------------------- /tests/generate_report.py: -------------------------------------------------------------------------------- 1 | import shlex, subprocess, os 2 | # Constructor 3 | 4 | if os.name == 'posix': 5 | OsType = 'linux' 6 | 7 | elif os.name == 'nt': 8 | OsType = 'Windows' 9 | 10 | elif os.name == 'os2': 11 | OsType = 'check' 12 | 13 | command_html_report = 'coverage html --omit=../GUI/*,../UnitTest/*,../Config/Validation.py,../Core/CustomException.py,../Core/Debugger.py' 14 | if OsType == 'Windows': 15 | startupinfo = subprocess.STARTUPINFO() 16 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 17 | 18 | process_response = subprocess.call(command_html_report, startupinfo=startupinfo) 19 | else: 20 | 21 | args = shlex.split(command_html_report) 22 | p = subprocess.Popen(args, stdout=subprocess.PIPE) 23 | -------------------------------------------------------------------------------- /Core/ProjectRepository.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | #!/usr/bin/env python 3 | # 4 | #@author: Furqan Wasi 5 | from Core import SharedApp 6 | 7 | class ProjectRepository(object): 8 | 9 | def __init__(self): 10 | self.Fixity = SharedApp.SharedApp.App 11 | 12 | def getAll(self): 13 | 14 | try:self.Fixity = SharedApp.SharedApp.App 15 | except:pass 16 | 17 | return self.Fixity.Database.getProjectInfo() 18 | 19 | def getSingleProject(self, project_name): 20 | """ 21 | Get Single Project 22 | 23 | @param project_name: 24 | 25 | @return: None 26 | """ 27 | 28 | try:self.Fixity = SharedApp.SharedApp.App 29 | except:pass 30 | 31 | try: 32 | selected_project_object = self.Fixity.ProjectsList[project_name] 33 | return selected_project_object 34 | except: 35 | return False 36 | -------------------------------------------------------------------------------- /tests/AllFixture/EmailFixtures.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | 9 | # built-in libraries 10 | import os 11 | 12 | # Custom libraries 13 | import sys 14 | import helper 15 | sys.path.append(helper.setImportBaseBath()) 16 | 17 | import Main 18 | from Fixtures import Fixtures 19 | 20 | 21 | class EmailFixtures(Fixtures): 22 | 23 | 24 | def __init__(self): 25 | self.App = Main.Main() 26 | super(EmailFixtures, self).__init__() 27 | self.information = {} 28 | 29 | self.information['email'] = 'test.bf007@gmail.com' 30 | self.information['pass'] = 'purelogics' 31 | self.information['smtp'] = 'smtp.gmail.com' 32 | self.information['protocol'] = 'ssl' 33 | self.information['port'] = '465' 34 | 35 | self.recipients = 'furqan@geekschicago.com' 36 | pass 37 | 38 | def EmailInformation(self): 39 | return self.information -------------------------------------------------------------------------------- /tests/assets/template/SchedulerMacDaily.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Program 6 | {{fixity_path}} 7 | Label 8 | {{demon_name}} 9 | ProgramArguments 10 | 11 | {{fixity_path}} 12 | -a={{project_name}} 13 | 14 | StandardOutPath 15 | {{debug_file_path}} 16 | StandardErrorPath 17 | {{debug_file_path}} 18 | StartCalendarInterval 19 | 20 | Minute 21 | {{mins}} 22 | Hour 23 | {{hrs}} 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /assets/template/SchedulerMacDaily.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Program 6 | /Applications/TextEdit.app/Contents/MacOS/TextEdit 7 | Label 8 | {{demon_name}} 9 | ProgramArguments 10 | 11 | /Applications/TextEdit.app/Contents/MacOS/TextEdit 12 | -a={{project_name}} 13 | 14 | StandardOutPath 15 | {{debug_file_path}} 16 | StandardErrorPath 17 | {{debug_file_path}} 18 | StartCalendarInterval 19 | 20 | Minute 21 | {{mins}} 22 | Hour 23 | {{hrs}} 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /assets/template/SchedulerMacMonth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Program 6 | {{fixity_path}} 7 | Label 8 | {{demon_name}} 9 | ProgramArguments 10 | 11 | {{fixity_path}} 12 | -a={{project_name}} 13 | 14 | StandardOutPath 15 | {{debug_file_path}} 16 | StandardErrorPath 17 | {{debug_file_path}} 18 | StartCalendarInterval 19 | 20 | Minute 21 | {{mins}} 22 | Hour 23 | {{hrs}} 24 | Day 25 | {{day}} 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /assets/template/SchedulerMacWeek.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Program 6 | {{fixity_path}} 7 | Label 8 | {{demon_name}} 9 | ProgramArguments 10 | 11 | {{fixity_path}} 12 | -a={{project_name}} 13 | 14 | StandardOutPath 15 | {{debug_file_path}} 16 | StandardErrorPath 17 | {{debug_file_path}} 18 | StartCalendarInterval 19 | 20 | Minute 21 | {{mins}} 22 | Hour 23 | {{hrs}} 24 | Weekday 25 | {{week_day}} 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/assets/template/SchedulerMacMonth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Program 6 | {{fixity_path}} 7 | Label 8 | {{demon_name}} 9 | ProgramArguments 10 | 11 | {{fixity_path}} 12 | -a={{project_name}} 13 | 14 | StandardOutPath 15 | {{debug_file_path}} 16 | StandardErrorPath 17 | {{debug_file_path}} 18 | StartCalendarInterval 19 | 20 | Minute 21 | {{mins}} 22 | Hour 23 | {{hrs}} 24 | Day 25 | {{day}} 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/assets/template/SchedulerMacWeek.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Program 6 | {{fixity_path}} 7 | Label 8 | {{demon_name}} 9 | ProgramArguments 10 | 11 | {{fixity_path}} 12 | -a={{project_name}} 13 | 14 | StandardOutPath 15 | {{debug_file_path}} 16 | StandardErrorPath 17 | {{debug_file_path}} 18 | StartCalendarInterval 19 | 20 | Minute 21 | {{mins}} 22 | Hour 23 | {{hrs}} 24 | Weekday 25 | {{week_day}} 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /assets/template/SchedulerWinDaily.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | {{days_interval}} 14 | 15 | 16 | 17 | 18 | true 19 | Parallel 20 | {{allow_start_on_demand}} 21 | {{allow_hard_terminate}} 22 | {{disallow_start_if_on_batteries}} 23 | {{start_when_available}} 24 | {{wake_to_run}} 25 | 26 | 27 | 28 | {{command}} 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/assets/template/SchedulerWinDaily.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | {{days_interval}} 14 | 15 | 16 | 17 | 18 | 19 | SYSTEM 20 | HighestAvailable 21 | 22 | 23 | 24 | true 25 | {{allow_start_on_demand}} 26 | {{allow_hard_terminate}} 27 | {{disallow_start_if_on_batteries}} 28 | {{start_when_available}} 29 | {{wake_to_run}} 30 | 31 | 32 | 33 | {{command}} 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /assets/template/SchedulerWinWeek.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | {{weeks_interval}} 14 | 15 | <{{day_of_week}}/> 16 | 17 | 18 | 19 | 20 | 21 | {{enabled}} 22 | Parallel 23 | {{allow_start_on_demand}} 24 | {{allow_hard_terminate}} 25 | {{disallow_start_if_on_batteries}} 26 | {{start_when_available}} 27 | {{wake_to_run}} 28 | 29 | 30 | 31 | {{command}} 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Core/CustomException.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | 7 | ''' 8 | import sys, os, traceback 9 | 10 | 11 | class CustomException(object): 12 | 13 | 14 | _instance = None 15 | 16 | @staticmethod 17 | def getInstance(): 18 | if not isinstance(CustomException._instance, CustomException): 19 | CustomException._instance = object.__new__(CustomException) 20 | return CustomException._instance 21 | 22 | def selfDestruct(self): 23 | del self 24 | 25 | def getExceptionDetails(self): 26 | """ 27 | Get Exception Details 28 | 29 | @return: List 30 | """ 31 | exc_type, exc_obj, exc_tb = sys.exc_info() 32 | file_name = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 33 | error_information = {} 34 | try: 35 | error_information['file_name'] = file_name 36 | except: 37 | pass 38 | 39 | try: 40 | error_information['error_type'] = exc_type 41 | except: 42 | pass 43 | try: 44 | error_information['line_no'] = exc_tb.tb_lineno 45 | except: 46 | pass 47 | 48 | return error_information 49 | 50 | def getTraceBack(self): 51 | """ 52 | Get Trace Back 53 | 54 | @return: Error Stack 55 | """ 56 | stack_errro = repr(traceback.extract_stack()) 57 | return stack_errro 58 | 59 | -------------------------------------------------------------------------------- /assets/template/SchedulerWinDailyAdmin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | {{days_interval}} 14 | 15 | 16 | 17 | 18 | 19 | SYSTEM 20 | HighestAvailable 21 | 22 | 23 | 24 | true 25 | Parallel 26 | {{allow_start_on_demand}} 27 | {{allow_hard_terminate}} 28 | {{disallow_start_if_on_batteries}} 29 | {{start_when_available}} 30 | {{wake_to_run}} 31 | 32 | 33 | 34 | {{command}} 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/assets/template/SchedulerWinWeek.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | {{weeks_interval}} 14 | 15 | <{{day_of_week}}/> 16 | 17 | 18 | 19 | 20 | 21 | 22 | SYSTEM 23 | HighestAvailable 24 | 25 | 26 | 27 | {{enabled}} 28 | {{allow_start_on_demand}} 29 | {{allow_hard_terminate}} 30 | {{disallow_start_if_on_batteries}} 31 | {{start_when_available}} 32 | {{wake_to_run}} 33 | 34 | 35 | 36 | {{command}} 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /assets/template/SchedulerWinWeekAdmin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | {{weeks_interval}} 14 | 15 | <{{day_of_week}}/> 16 | 17 | 18 | 19 | 20 | 21 | 22 | SYSTEM 23 | HighestAvailable 24 | 25 | 26 | 27 | {{enabled}} 28 | Parallel 29 | {{allow_start_on_demand}} 30 | {{allow_hard_terminate}} 31 | {{disallow_start_if_on_batteries}} 32 | {{start_when_available}} 33 | {{wake_to_run}} 34 | 35 | 36 | 37 | {{command}} 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/AllFixture/RequiredsCreationFixture.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | 9 | # built-in libraries 10 | import os 11 | 12 | from Fixtures import Fixtures 13 | # Custom libraries 14 | 15 | import sys 16 | import shutil 17 | 18 | import helper 19 | sys.path.append(helper.setImportBaseBath()) 20 | 21 | import Main 22 | 23 | 24 | class RequiredsCreationFixture(Fixtures): 25 | 26 | 27 | def __init__(self): 28 | self.App = Main.Main() 29 | super(RequiredsCreationFixture, self).__init__() 30 | self.base_folder = self.App.Fixity.Configuration.getBasePath() 31 | pass 32 | 33 | def removeDirsAndFiles(self): 34 | 35 | try: 36 | os.remove(self.base_folder + 'Fixity.db') 37 | except: 38 | pass 39 | 40 | try: 41 | os.remove(self.base_folder + 'conf.xml') 42 | except: 43 | pass 44 | 45 | try: 46 | os.remove(self.base_folder + 'debug.log') 47 | except: 48 | pass 49 | 50 | try: 51 | shutil.rmtree(self.base_folder + 'reports') 52 | except: 53 | pass 54 | 55 | try: 56 | shutil.rmtree(self.base_folder + 'history') 57 | except: 58 | pass 59 | 60 | try: 61 | shutil.rmtree(self.base_folder + 'schedules') 62 | except: 63 | pass 64 | 65 | pass 66 | 67 | def createDirsAndFiles(self): 68 | self.removeDirsAndFiles() 69 | self.App = Main.Main() 70 | self.App.Fixity.Setup.setupApp() 71 | pass -------------------------------------------------------------------------------- /assets/template/SchedulerWinMonth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | 14 | {{days_of_month}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | {{enabled}} 35 | Parallel 36 | {{allow_start_on_demand}} 37 | {{allow_hard_terminate}} 38 | {{disallow_start_if_on_batteries}} 39 | {{start_when_available}} 40 | {{wake_to_run}} 41 | 42 | 43 | 44 | {{command}} 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /tests/assets/template/SchedulerWinMonth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | 14 | {{days_of_month}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | SYSTEM 36 | HighestAvailable 37 | 38 | 39 | 40 | {{enabled}} 41 | {{allow_start_on_demand}} 42 | {{allow_hard_terminate}} 43 | {{disallow_start_if_on_batteries}} 44 | {{start_when_available}} 45 | {{wake_to_run}} 46 | 47 | 48 | 49 | {{command}} 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /assets/template/SchedulerWinMonthAdmin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{current_data_time}} 5 | {{user}} 6 | {{version}} 7 | Fixity Task Scheduler to Monitor A Folder Activity! 8 | 9 | 10 | 11 | {{start_boundary}} 12 | 13 | 14 | {{days_of_month}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | SYSTEM 36 | HighestAvailable 37 | 38 | 39 | 40 | {{enabled}} 41 | Parallel 42 | {{allow_start_on_demand}} 43 | {{allow_hard_terminate}} 44 | {{disallow_start_if_on_batteries}} 45 | {{start_when_available}} 46 | {{wake_to_run}} 47 | 48 | 49 | 50 | {{command}} 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /tests/TestCases/ExpectedResults.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on July 10, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | EmailTestCaseExpectedResult = {} 9 | EmailTestCaseExpectedResult['testing'] = True 10 | EmailTestCaseExpectedResult['attachment'] = True 11 | EmailTestCaseExpectedResult['error'] = True 12 | 13 | RequiredsCreationTestCaseExpectedResult = {} 14 | RequiredsCreationTestCaseExpectedResult['all'] = True 15 | 16 | ProjectTestCaseExpectedResult = {} 17 | ProjectTestCaseExpectedResult['run_project'] = 4 18 | ProjectTestCaseExpectedResult['delete_project'] = True 19 | ProjectTestCaseExpectedResult['change_project_name'] = True 20 | ProjectTestCaseExpectedResult['change_algorithm'] = False 21 | ProjectTestCaseExpectedResult['import_project'] = True 22 | ProjectTestCaseExpectedResult['save_project'] = True 23 | 24 | # 0 = Confirmed 25 | # 1 = Missing File 26 | # 2 = Created 27 | # 3 = Moved 28 | # 4 = Corrupted Or Changed 29 | 30 | ProjectTestCaseExpectedResult['filters_files'] = {0: 3, 1: 1, 2: 0, 3: 0, 4: 0} 31 | 32 | AlgorithmTestCaseExpectedResult = {} 33 | AlgorithmTestCaseExpectedResult['test_confirm_file'] = {0: 4, 1: 0, 2: 0, 3: 0, 4: 0} 34 | AlgorithmTestCaseExpectedResult['test_confirm_if_inode_changed_of_file'] = {0: 4, 1: 0, 2: 0, 3: 0, 4: 0} 35 | AlgorithmTestCaseExpectedResult['test_delete_file'] = {0: 3, 1: 1, 2: 0, 3: 0, 4: 0} 36 | AlgorithmTestCaseExpectedResult['test_change_file'] = {0: 3, 1: 0, 2: 0, 3: 0, 4: 1} 37 | AlgorithmTestCaseExpectedResult['test_change_file_changed_hash_and_path'] = {0: 3, 1: 0, 2: 0, 3: 0, 4: 1} 38 | AlgorithmTestCaseExpectedResult['test_change_inode_and_hash_file'] = {0: 3, 1: 0, 2: 0, 3: 0, 4: 1} 39 | AlgorithmTestCaseExpectedResult['test_new_file'] = {0: 4, 1: 0, 2: 1, 3: 0, 4: 0} 40 | AlgorithmTestCaseExpectedResult['test_moved_file'] = {0: 3, 1: 0, 2: 0, 3: 1, 4: 0} 41 | AlgorithmTestCaseExpectedResult['test_moved_file_to_new_directory'] = {0: 3, 1: 0, 2: 0, 3: 1, 4: 0} 42 | AlgorithmTestCaseExpectedResult['test_moved_file_to_new_Directory_change_hash'] = {0: 3, 1: 0, 2: 0, 3: 0, 4: 1} 43 | AlgorithmTestCaseExpectedResult['test_moved_file_to_new_Directory_change_name_as_old'] = {0: 4, 1: 0, 2: 0, 3: 0, 4: 0} 44 | AlgorithmTestCaseExpectedResult['test_moved_to_new_Directory_change_name_as_old_and_content'] = {0: 3, 1: 0, 2: 0, 3: 0, 4: 1} 45 | AlgorithmTestCaseExpectedResult['test_change_base_path'] = {0: 4, 1: 0, 2: 0, 3: 0, 4: 0} 46 | AlgorithmTestCaseExpectedResult['test_intersection_of_dir'] = {0: 4, 1: 0, 2: 0, 3: 0, 4: 0} -------------------------------------------------------------------------------- /tests/documentation.md: -------------------------------------------------------------------------------- 1 | # How to Run Unit Test 2 | ##### Command to Run Unit Test 3 | ###### coverage run TestSuite.py 4 | 5 | ##### Command to Generate Html Report 6 | ###### python generate_report.py 7 | 8 | 9 | # List of Unit Tests For Fixity 10 | ######There are about 26 unit test writen for fixity 11 | 12 | ### All unit test contains 13 | ######Algorithum changes unit test for conditions mentioned below 14 | 15 | #####Confirm for Both Normal And Special Charachter 16 | 17 | 1. Confirmed FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::NO 18 | 2. Confirmed FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 19 | 20 | #####Changed for Both Normal And Special Charachter 21 | 22 | 1. Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::YES ||SameI-Node::YES 23 | 2. Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::NO ||SameI-Node::YES 24 | 3. Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::YES ||SameI-Node::NO 25 | 26 | #####Moved for Both Normal And Special Charachter 27 | 1. Moved FileExists::YES ||SameHashOfFile::YES ||SameFilePath::NO ||SameI-Node::YES 28 | 29 | #####Removed for Both Normal And Special Charachter 30 | 1. Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 31 | 32 | #####New for Both Normal And Special Charachter 33 | 1. New FileExists::YES ||SameHashOfFile::NO ||SameFilePath::NO ||SameI-Node::NO 34 | 35 | #####Scenarios of Algorithm change 36 | 1. Move file with in a directory 37 | 2. Move file with in a directory and change content 38 | 3. Copy , Paste a File 39 | 4. Copy , Paste a File , Then Remove old File also change name of the new file as old one 40 | 5. Copy , Paste a File , Then Remove old File and change content of New file also change name of the new file as old one 41 | 6. Change Directories Path 42 | 7. Intersection of folder at a new place 43 | 44 | ###Scenarios of Dir required 45 | 1. Is Report Directory Exists 46 | 2. Is Schedules Directory Exists 47 | 3. Is Config File Exists 48 | 4. Is Debug File Exists 49 | 5. Is Database File Exists 50 | 6. Is History Directory Exist 51 | 52 | ###Project Operations 53 | 54 | 1. Delete Run Unit test 55 | 2. Project Run Unit test 56 | 3. Change Project Name Unit test 57 | 4. Save Project Unit test 58 | 5. Change Algorithm Unit test 59 | 6. Filter scanned files Unit test 60 | 7. Import Project Unit test 61 | 62 | ###Email Unit Test 63 | 1. Testing Email 64 | 2. Attchment Email 65 | 3. Error Email 66 | 67 | -------------------------------------------------------------------------------- /tests/TestCases/EmailTestCase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | # built-in libraries 9 | import unittest 10 | import os 11 | import sys 12 | 13 | # Custom libraries 14 | from AllFixture.EmailFixtures import EmailFixtures 15 | from Core import EmailNotification 16 | import ExpectedResults as ExpectedResults 17 | import FailedMessages as FailedMessages 18 | 19 | import AllFixture.helper as helper 20 | sys.path.append(helper.setImportBaseBath()) 21 | 22 | import Main 23 | 24 | 25 | class EmailTestCase(object): 26 | 27 | 28 | def __init__(self): 29 | self.App = Main.Main() 30 | self.email_fixtures = EmailFixtures() 31 | self.email_notification = EmailNotification.EmailNotification() 32 | pass 33 | 34 | def test_testing_email(self): 35 | """ 36 | Testing Email 37 | 38 | @return: None 39 | """ 40 | print('Testing Email..........!') 41 | response = self.email_notification.TestingEmail(self.email_fixtures.recipients, 'Testing the Email', self.email_fixtures.EmailInformation()) 42 | 43 | print("---------------------------------------------------------------------\n") 44 | 45 | return [response, ExpectedResults.EmailTestCaseExpectedResult['testing'], FailedMessages.EmailTestCaseFailMessages['testing']] 46 | pass 47 | 48 | def test_attachment_email(self): 49 | """ 50 | Test Attachment Email 51 | 52 | @return: None 53 | """ 54 | print('Attachment Email..........!') 55 | self.email_fixtures.load_attachment() 56 | response = self.email_notification.ReportEmail(self.email_fixtures.recipients, self.email_fixtures.attachment ,'Testing the Email' ,self.email_fixtures.EmailInformation(), self.email_fixtures.project_name) 57 | self.email_fixtures.unload_attachment() 58 | 59 | print("---------------------------------------------------------------------\n") 60 | 61 | return [response, ExpectedResults.EmailTestCaseExpectedResult['attachment'], FailedMessages.EmailTestCaseFailMessages['attachment']] 62 | 63 | def test_Error_email(self): 64 | """ 65 | Test Error Email 66 | 67 | @return: None 68 | """ 69 | print('Error Email..........!') 70 | self.email_fixtures.load_attachment() 71 | response = self.email_notification.ErrorEmail(self.email_fixtures.recipients, self.email_fixtures.attachment ,'Testing the Email' ,self.email_fixtures.EmailInformation(), self.email_fixtures.project_name) 72 | self.email_fixtures.unload_attachment() 73 | 74 | print("---------------------------------------------------------------------\n") 75 | 76 | return [response, ExpectedResults.EmailTestCaseExpectedResult['error'], FailedMessages.EmailTestCaseFailMessages['error']] -------------------------------------------------------------------------------- /GUI/NotificationGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | from PySide.QtCore import * 9 | from PySide.QtGui import * 10 | 11 | 12 | ''' 13 | Pop Up Messages, handler 14 | ''' 15 | 16 | 17 | class NotificationGUI(QMessageBox): 18 | 19 | 20 | ''' 21 | Constructor 22 | ''' 23 | def __init__(self): 24 | ''' QMessageBox Constructor ''' 25 | super(NotificationGUI,self).__init__() 26 | 27 | 28 | ''' 29 | Show Error Message 30 | 31 | @param Object parent: Parent Or Called Instance 32 | @param String heading: heading of the Pop Up 33 | @param String message: Message of The Pop Up 34 | 35 | @return None 36 | 37 | ''' 38 | def showError(self,parent,heading,message): 39 | self.critical(parent, heading, message) 40 | return 41 | 42 | 43 | ''' 44 | Show Error Message 45 | 46 | @param Object parent: Parent Or Called Instance 47 | @param String heading: heading of the Pop Up 48 | @param String message: Message of The Pop Up 49 | 50 | @return None 51 | 52 | ''' 53 | def showWarning(self,parent,heading,message): 54 | self.warning(parent, heading, message) 55 | return 56 | 57 | 58 | ''' 59 | Show Question Message 60 | 61 | @param Object parent: Parent Or Called Instance 62 | @param String heading: heading of the Pop Up 63 | @param String message: Message of The Pop Up 64 | 65 | @return Boolean: response by User 66 | 67 | ''' 68 | def showQuestion(self,parent,heading,message): 69 | response = self.question(parent, heading, message, self.Yes | self.No) 70 | 71 | result = { 72 | self.Yes: True, 73 | self.No:False, 74 | self.Cancel:False 75 | } 76 | 77 | 78 | return result[response] 79 | 80 | 81 | ''' 82 | Show Question Message 83 | 84 | @param Object parent: Parent Or Called Instance 85 | @param String heading: heading of the Pop Up 86 | @param String message: Message of The Pop Up 87 | 88 | @return None 89 | 90 | ''' 91 | def showInformation(self,parent,heading,message): 92 | self.information(parent, heading, message) 93 | return 94 | 95 | # app = QApplication('asd') 96 | # N = Notifications() 97 | # N.showQuestion(N,'testing','asdas asdasasdasasdasasdasasdasasdasasdas') 98 | # N.showWarning(N,'testing','asdas asdasasdasasdasasdasasdasasdasasdas') 99 | # N.showError(N,'testing','asdas asdasasdasasdasasdasasdasasdasasdas') 100 | # N.showInformation(N,'testing','asdas asdasasdasasdasasdasasdasasdasasdas') 101 | # 102 | # exit(app.exec_()) -------------------------------------------------------------------------------- /App.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | from Config import Configuration, Validation, Setup 9 | from GUI import GUILibraries, ProjectGUI 10 | from Core import Debugger, Database, CustomException, SharedApp, ProjectCore, ProjectRepository 11 | from Queue import Queue 12 | 13 | class App(object): 14 | _instance = None 15 | def __init__(self): 16 | self.setUp() 17 | 18 | def selfDestruct(self): 19 | del self 20 | 21 | @staticmethod 22 | def getInstance(is_unit_test): 23 | if not isinstance(App._instance, App): 24 | App._instance = object.__new__(App) 25 | SharedApp.SharedApp.App = App._instance 26 | App._instance.setUp(is_unit_test) 27 | return App._instance 28 | 29 | def setUp(self, is_unit_test): 30 | self.ExceptionHandler = CustomException.CustomException.getInstance() 31 | self.Configuration = Configuration() 32 | self.Validation = Validation 33 | self.Setup = Setup.Setup() 34 | self.Setup.setupApp() 35 | self.logger = Debugger.Debugger.getInstance() 36 | self.Database = Database.Database.getInstance(is_unit_test) 37 | self.Database.connect(is_unit_test) 38 | self.ProjectGUI = ProjectGUI 39 | self.Setup.createTables() 40 | self.ProjectRepo = ProjectRepository.ProjectRepository() 41 | 42 | email_configuration = self.Database.getConfiguration() 43 | 44 | try: 45 | self.Configuration.setEmailConfiguration(email_configuration[0]) 46 | except: 47 | self.Configuration.setEmailConfiguration(email_configuration) 48 | pass 49 | 50 | self.ProjectsList = {} 51 | self.queue = {} 52 | 53 | self.loadAllProjects() 54 | 55 | def loadAllProjects(self): 56 | all_projects = self.ProjectRepo.getAll() 57 | 58 | 59 | if all_projects is not None and all_projects is not False: 60 | if len(all_projects) > 0: 61 | for single_project in all_projects: 62 | project_logic = ProjectCore.ProjectCore() 63 | project_logic.setProjectInfo(all_projects[single_project]) 64 | self.ProjectsList[all_projects[single_project]['title']] = project_logic 65 | 66 | def getSingleThreadToQueue(self, thread_id): 67 | return self.queue.get(thread_id) 68 | 69 | def addSingleThreadToQueue(self, thread_id, thread_object): 70 | return self.queue.put(thread_object) 71 | 72 | def getProjectList(self): 73 | information = [] 74 | if self.ProjectsList is not None and self.ProjectsList is not False: 75 | if len(self.ProjectsList) > 0: 76 | for project in self.ProjectsList: 77 | information.append(str(self.ProjectsList[project].getTitle())) 78 | return information 79 | 80 | def getSingleProject(self, project_name): 81 | try: 82 | selected_project_object = self.ProjectsList[project_name] 83 | return selected_project_object 84 | except: 85 | return False 86 | 87 | def removeProject(self, project_name): 88 | self.ProjectsList.__delitem__(project_name) -------------------------------------------------------------------------------- /tests/AllFixture/ProjectFixtures.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | # built-in libraries 9 | from Fixtures import Fixtures 10 | 11 | # Custom libraries 12 | import sys 13 | import helper 14 | sys.path.append(helper.setImportBaseBath()) 15 | 16 | import Main 17 | 18 | 19 | class ProjectFixtures(Fixtures): 20 | 21 | 22 | def __init__(self): 23 | self.App = Main.Main() 24 | super(ProjectFixtures, self).__init__() 25 | self.unit_test_folder = self.App.Fixity.Configuration.getUnit_test_folder() 26 | self.filters = '.txt' 27 | self.is_ignore_hidden_files = True 28 | pass 29 | 30 | def create_new_project(self, project_name, is_special_chars = False): 31 | """ 32 | Del File 33 | 34 | @param project_name: Project Name 35 | @param is_special_chars: 36 | @return: 37 | """ 38 | project_information = {} 39 | 40 | project_information['title'] = project_name 41 | project_information['ignoreHiddenFiles'] = '' 42 | project_information['selectedAlgo'] = 'sha256' 43 | project_information['filters'] = '' 44 | project_information['durationType'] = '2' 45 | project_information['runTime'] = '' 46 | project_information['runDayOrMonth'] = '0' 47 | project_information['runWhenOnBattery'] = '1' 48 | project_information['ifMissedRunUponRestart'] = '1' 49 | project_information['versionCurrentID'] = '1' 50 | project_information['emailOnlyUponWarning'] = '1' 51 | 52 | project_information['emailAddress'] = '' 53 | project_information['extraConf'] = '' 54 | project_information['lastRan'] = '' 55 | 56 | project_information['updatedAt'] = self.App.Fixity.Configuration.getCurrentTime() 57 | 58 | project_id = self.App.Fixity.Database.insert(self.App.Fixity.Database._tableProject, project_information) 59 | dir_information = {} 60 | if is_special_chars: 61 | dirs_path = self.unit_test_folder_special 62 | else: 63 | dirs_path = self.unit_test_folder 64 | 65 | for n in range(self.App.Fixity.Configuration.number_of_path_directories): 66 | 67 | dir_information['path'] = dirs_path 68 | dir_information['pathID'] = 'Fixity-'+str((n + 1)) 69 | dir_information['projectID'] = project_id['id'] 70 | dir_information['versionID'] = '1' 71 | dir_information['updatedAt'] = self.App.Fixity.Configuration.getCurrentTime() 72 | dir_information['createdAt'] = self.App.Fixity.Configuration.getCurrentTime() 73 | 74 | dir_new_id = self.App.Fixity.Database.insert(self.App.Fixity.Database._tableProjectPath, dir_information) 75 | dirs_path = '' 76 | self.App.Fixity.loadAllProjects() 77 | return dir_new_id 78 | 79 | def delete_project(self, project_name, project_id): 80 | """ 81 | Delete Project 82 | """ 83 | 84 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableProjectPath, 'projectID="' + str(project_id) + '"') 85 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableVersionDetail, 'projectID="' + str(project_id) + '"') 86 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableProject, 'id ="' + str(project_id) + '"') -------------------------------------------------------------------------------- /fileVerificationMethod.md: -------------------------------------------------------------------------------- 1 | Created By Furqan Wasi Create On 7/5/2014 Wednesday,May 2 | 3 | #Fixity File Verification Logic 4 | ###Receives Single File information to be verified 5 | 6 | 1. Check if given file exists at given path 7 | 1. Check if any file exists for given inode in last scanned file's list 8 | 2. If file exists and inode exists in last scan ( means file is still present and was also have been scanned by Fixity in it's last scan) 9 | 10 | 1. if File Exists::YES AND Hashes are Same of File in last scan and given file::YES AND Have Same File Path of File in last scan and given file::YES AND Have Same I-Node of File in last scan and given file::YES 11 | * `Result :: Confirmed File (FileExists::YES || SameHashOfFile::YES || SameFilePath::YES || Same I-Node::YES)` 12 | 2. if File Exists::YES AND Hashes are Same of File in last scan and given file::YES AND Have Same File Path of File in last scan and given file::NO AND Have Same I-Node of File in last scan and given file::YES 13 | * `Result :: Moved or Renamed File (FileExists::YES ||SameHashOfFile::YES || SameFilePath::NO || Same I-Node::YES)` 14 | 3. if File Exists::YES AND Hashes are Same of File in last scan and given file::NO AND Have Same File Path of File in last scan and given file::YES AND Have Same I-Node of File in last scan and given file::YES 15 | * `Result :: Changed File (FileExists::YES || SameHashOfFile::NO || SameFilePath::YES || Same I-Node::YES)` 16 | 4. if File Exists::YES AND Hashes are Same of File in last scan and given file::NO AND Have Same File Path of File in last scan and given file::NO AND Have Same I-Node of File in last scan and given file::YES 17 | * `Result :: Changed File (FileExists::YES || SameHashOfFile::NO || SameFilePath::NO || Same I-Node::YES)` 18 | 19 | 3. If file exists and file with same hash exists but inode dose not exists in last scan ( means file is still present and file with same hash exists but was not existing in directory , or was not scanned for some reason (could be because of filters)) 20 | 21 | 1. if File Exists::YES AND Hashes are Same of File in last scan and given file::YES AND Have Same File Path of File in last scan and given file::YES AND Have Same I-Node of File in last scan and given file::NO 22 | * `Result :: Confirmed File (FileExists::YES || SameHashOfFile::YES || SameFilePath::YES || Same I-Node::NO)` 23 | 24 | 2. if File Exists::YES AND Hashes are Same of File in last scan and given file::NO AND Have Same File Path of File in last scan and given file::YES AND Have Same I-Node of File in last scan and given file::NO ''' 25 | * `Result :: Moved or Renamed File (FileExists::YES || SameHashOfFile::NO || SameFilePath::YES || Same I-Node::NO)` 26 | 27 | 3. if File Exists::YES AND Hashes are Same of File in last scan and given file::YES AND Have Same File Path of File in last scan and given file::NO AND Have Same I-Node of File in last scan and given file::NO ''' 28 | * `Result :: Changed File (FileExists::YES || SameHashOfFile::YES || SameFilePath::NO || Same I-Node::NO)` 29 | 30 | 4. If file exists but file with same hash dont exist and inode dose not exists in last scan ( means file is still present and file with same hash exists but was not existing in directory , or was not scanned for some reason (could be because of filters)) 31 | * `Result :: New File (FileExists::YES || SameHashOfFile::NO || SameFilePath::NO || Same I-Node::NO)` 32 | 33 | 2) Check if given file do not exist at given path and didnot fall in any of above condition will be considered as Removed 34 | * `Result :: Removed File` 35 | -------------------------------------------------------------------------------- /tests/TestCases/FailedMessages.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | EmailTestCaseFailMessages = {} 9 | ProjectTestCaseFailMessages = {} 10 | AlgorithmTestCaseFailMessages = {} 11 | RequiredsCreationTestCaseFailMessages = {} 12 | 13 | EmailTestCaseFailMessages['testing'] = 'Failed Testing Email ................. !' 14 | EmailTestCaseFailMessages['attachment'] = 'Failed Attachment Email ................. !' 15 | EmailTestCaseFailMessages['error'] = 'Failed Error Email ................. !' 16 | 17 | ProjectTestCaseFailMessages['run_project'] = 'Failed Run Project Unit Test ................. !' 18 | ProjectTestCaseFailMessages['delete_project'] = "Failed Delete Project Unit Test ................. !" 19 | ProjectTestCaseFailMessages['change_project_name'] = "Failed Change Project Name Unit Test ................. !" 20 | ProjectTestCaseFailMessages['change_algorithm'] = "Failed Algo Change Unit Test ................. !" 21 | ProjectTestCaseFailMessages['filters_files'] = 'Failed Filters Project files ................. !' 22 | ProjectTestCaseFailMessages['import_project'] = "Failed Import Project Unit Test ................. !" 23 | ProjectTestCaseFailMessages['save_project'] = "Failed Save Project Unit Test ................. !" 24 | 25 | AlgorithmTestCaseFailMessages['test_confirm_file'] = "Failed Confirm File Unit Test ................. !" 26 | AlgorithmTestCaseFailMessages['test_confirm_if_inode_changed_of_file'] = 'Failed Confirm File Unit Test ................. !' 27 | AlgorithmTestCaseFailMessages['test_delete_file'] = 'Failed Delete File Unit Test ................. !' 28 | AlgorithmTestCaseFailMessages['test_change_file'] = 'Failed Change File {( Only Hash Changed )} Unit Test ................. !' 29 | AlgorithmTestCaseFailMessages['test_change_file_changed_hash_and_path'] = 'Failed Change File {( Hash and Path Changed )} Unit Test ................. !' 30 | AlgorithmTestCaseFailMessages['test_change_inode_and_hash_file'] = 'Failed Change File {( I-Node and Hash Changed )} Unit Test ................. !' 31 | AlgorithmTestCaseFailMessages['test_new_file'] = 'Failed New File Unit Test ................. !' 32 | AlgorithmTestCaseFailMessages['test_moved_file'] = 'Failed New File Unit Test ................. !' 33 | AlgorithmTestCaseFailMessages['test_moved_file_to_new_directory'] = 'Failed Moved File into a Directory Unit Test ................. !' 34 | AlgorithmTestCaseFailMessages['test_moved_file_to_new_Directory_change_hash'] = 'Failed Moved into a Directory and Changed Hash of a File Unit Test ................. !' 35 | AlgorithmTestCaseFailMessages['test_moved_file_to_new_Directory_change_name_as_old'] = 'Failed Copy , Paste a File , Then Remove old File also change name of the new file as old one Unit Test ................. !' 36 | AlgorithmTestCaseFailMessages['test_moved_to_new_Directory_change_name_as_old_and_content'] = 'Failed Copy , Paste a File , Then Remove old File also change name of the new file as old one and changed content Unit Test ................. !' 37 | AlgorithmTestCaseFailMessages['test_change_base_path'] = 'Failed Test Change Base Path Unit Test ................. !' 38 | AlgorithmTestCaseFailMessages['test_intersection_of_dir'] = 'Failed Test Intersection Of Dir Unit Test ................. !' 39 | 40 | RequiredsCreationTestCaseFailMessages['is_report_dir_exists'] = 'Failed Reports Directory Creation Unit Test ................. !' 41 | RequiredsCreationTestCaseFailMessages['is_history_dir_exists'] = 'Failed History Directory Creation Unit Test ................. !' 42 | RequiredsCreationTestCaseFailMessages['is_schedules_dir_exists'] = 'Failed Scheduler Directory Creation Unit Test ................. !' 43 | RequiredsCreationTestCaseFailMessages['is_config_file_exists'] = 'Failed Configuration Directory Creation Unit Test ................. !' 44 | RequiredsCreationTestCaseFailMessages['is_database_file_exists'] = 'Failed Database Directory Creation Unit Test ................. !' 45 | RequiredsCreationTestCaseFailMessages['is_debug_files_exists'] = 'Failed Debug Directory Creation Unit Test ................. !' 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | from os import path 8 | from Core import SharedApp, DatabaseLockHandler 9 | from GUI import GUILibraries 10 | import App 11 | from argparse import ArgumentParser 12 | import sys, os, traceback, logging 13 | 14 | sys.path.append('/usr/local/lib/python2.7') 15 | sys.path.append('/usr/local/lib/python2.7/site-packages') 16 | sys.path.append('/usr/local/lib/python2.7/site-packages/PySide') 17 | 18 | class Main (object): 19 | 20 | def __init__(self, is_unit_test = False): 21 | SharedApp.SharedApp.App = App.App.getInstance(is_unit_test) 22 | self.Fixity = SharedApp.SharedApp.App 23 | self.Fixity.is_unit_test = is_unit_test 24 | 25 | def LaunchGUI(self, arg): 26 | app = GUILibraries.QApplication(arg) 27 | app.MainFixityWindow = App.ProjectGUI.ProjectGUI() 28 | app.MainFixityWindow.show() 29 | 30 | app.exec_() 31 | 32 | def LaunchCLI(self, project_name, called_from = 'CLI', new_path=None): 33 | 34 | is_lock_exists = False 35 | is_dead_lock = False 36 | 37 | try: 38 | process_id = os.getpid() 39 | except: 40 | process_id = None 41 | pass 42 | 43 | 44 | # Get File Locker and check for dead lock 45 | try: 46 | lock = DatabaseLockHandler.DatabaseLockHandler(self.Fixity.Configuration.getLockFilePath(),process_id, timeout=20) 47 | 48 | is_dead_lock = lock.isProcessLockFileIsDead() 49 | except: 50 | self.Fixity.logger.LogException(Exception.message) 51 | print(Exception.message) 52 | pass 53 | 54 | try: 55 | if is_dead_lock: 56 | lock.is_locked = True 57 | lock.release() 58 | except: 59 | self.Fixity.logger.LogException(Exception.message) 60 | pass 61 | 62 | try: 63 | is_lock_exists = lock.isLockFileExists() 64 | except: 65 | pass 66 | 67 | project_core = self.Fixity.ProjectRepo.getSingleProject(project_name) 68 | if is_lock_exists is False: 69 | if new_path is not None: 70 | dir_information = {} 71 | dir_information['path'] = new_path 72 | 73 | self.Fixity.Database.update(self.Fixity.Database._tableProjectPath, dir_information, '1 = 1') 74 | 75 | for dirs_objects in project_core.directories: 76 | project_core.directories[dirs_objects].setPath(new_path) 77 | break 78 | 79 | project_core.Save(False) 80 | if called_from == 'test': 81 | return project_core.Run(False, False, False, 'test') 82 | else: 83 | project_core.Run() 84 | else: 85 | print('Fixity is already scanning a project.\nPlease wait until the current scan completes before starting a new one.') 86 | return '' 87 | def log_uncaught_exceptions(ex_cls, ex, tb): 88 | 89 | logging.critical(''.join(traceback.format_tb(tb))) 90 | logging.critical('{0}: {1}'.format(ex_cls, ex)) 91 | 92 | if __name__ == '__main__': 93 | try: 94 | parser = ArgumentParser() 95 | parser.add_argument('-a', '--autorun') 96 | args = parser.parse_args() 97 | except: 98 | pass 99 | # sys.excepthook = log_uncaught_exceptions 100 | # If Received argument (project name and run command), it with run the 101 | # scheduler other wise it will open Fixity Front end View) 102 | Fixity = Main(False) 103 | if args.autorun is None or args.autorun == '': 104 | Fixity.LaunchGUI(sys.argv) 105 | else: 106 | try: 107 | Fixity.LaunchCLI(args.autorun) 108 | except: 109 | exc_type, exc_obj, exc_tb = sys.exc_info() 110 | file_name = path.split(exc_tb.tb_frame.f_code.co_filename)[1] 111 | 112 | print("Could not run this Project "+str(Exception.message)) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Fixity 2 | 3 | Find extensive user documentation at https://www.avpreserve.com/tools/fixity/ 4 | 5 | Created By Furqan Wasi furqan@avpreserve.com, April, 14, 2014. 6 | 7 | ## Directory Structure 8 | 9 | ./build (Stores file required to create stand alone application) 10 | 11 | ./dist (contains Stand Alone app after creating using py2app or pyinstaller) 12 | 13 | ./history (Contain Manifest files of the project as history) 14 | 15 | ./assets (images using in Fixity and templates for scheduler xml templates) 16 | 17 | ./reports (Contains generated Reports) 18 | 19 | ./schedules (contains files used in scheduling process) 20 | 21 | ## Code Structure 22 | 23 | +---assets (Images and templates ) (Sub Directory ) +---template (templates of scheduler xml file creation) 24 | 25 | +---Config (Files mentaion Fixity Setting up and Configuration ) 26 | 27 | +---Core (Files Contains all business logic for Fixity ) 28 | 29 | +---GUI (Files Contains all GUI for Fixity ) 30 | 31 | ## Files information 32 | 33 | ./conf.xml (contain information is debugging on or off ) 34 | ./Fixity.db (Database of Fixity contains all information except dubugging is on or off) 35 | ./debug.log (Exceptions and error Logging ) 36 | 37 | ## Mac Configuration 38 | 1. Download and install latest Xcode compatible with your macOS version 39 | 40 | 2. Download and install QT 4.8 (witout debug-libraries) http://qt-project.org/downloads 41 | 42 | 3. Download and install PySide (http://qt-project.org/wiki/PySide_Binaries_MacOSX) 43 | 44 | 4. Download and install favorite IDE (PyCharm,Textmate,eclipse) 45 | 46 | 5. install from mac port or brew 47 | 48 | install cmake install qmake 49 | 50 | 6. Install PySide using easyinstall:: sudo easy_install-2.7 PySide 51 | 52 | 7. Upgrade PySide sudo easy_install-2.7 -U PySide 53 | 54 | ## For App Creation 55 | py2applet --make-setup MyApplication.py 56 | 57 | rm -rf build dist 58 | 59 | python setup.py py2app 60 | 61 | new app will be create in "dist" folder 62 | 63 | For More Information Visist:https://pythonhosted.org/py2app/tutorial.html 64 | 65 | ## Scheduling Process 66 | Fixity is using launchd for scheduling , it save's plist for scheduling at "cd ~/Library/LaunchAgents/" , in this .plist file stores all scheduling information , for each project one .plist will be created. 67 | 68 | ## Windows Configuration 69 | 1. Download and install Python2.7 70 | 71 | 2. Download and install pyside1.2 72 | 73 | 2. Download and install QT4.8 74 | 75 | 3. Download and install PyInstaller 2.1 for .exe file create as stand alone application 76 | 77 | 4. Download and install favorite IDE (PyCharm,Textmate,eclipse) 78 | 79 | For eclipse from install new update , install pydev from python.org/updates and set interpreter as python from preferences 80 | 81 | 5. if having problem of missing library download and install them from python.org using python setup.py install (setup.py file will be provided in the given library package ) 82 | 83 | ## App/Executable File Creation 84 | python /path/to/pyinstaller/pyinstaller.py --onefile --noconsole --icon="assets\icon.ico" FileName.py 85 | 86 | In Fixity two Files are created 87 | 88 | python /path/to/pyinstaller/pyinstaller.py --onefile --noconsole --icon="assets\icon.ico" Fixity.py 89 | 90 | python /path/to/pyinstaller/pyinstaller.py --onefile --noconsole --icon="assets\icon.ico" AutoFixity.py 91 | 92 | These files are placed in "dist" directory after complilation of above commands 93 | 94 | Note: to turn on the debugging for app using --console 95 | 96 | when placing the file for the build 97 | 98 | Fixity.exe will be placed at the same level of all other directories for example (bin,schedules,history,etc) 99 | 100 | AutoFxity.py will be placed into schedules directory where from task scheduler will access it to run scanner 101 | 102 | ## Scheduling Process 103 | 104 | For scheduling process Fixity is using the Windows task scheduler. It triggers the scanning process at a given time when saving the project. For each project one scheduler will be created in the Windows task scheduler 105 | -------------------------------------------------------------------------------- /Core/DatabaseLockHandler.py: -------------------------------------------------------------------------------- 1 | # -- coding: utf-8 -- 2 | # 3 | #@author: Furqan Wasi 4 | import os 5 | import time 6 | import errno 7 | 8 | class DatabaseLockHandlerException(Exception): 9 | pass 10 | 11 | """ A file locking mechanism that has context-manager support so 12 | you can use it in a with statement. This should be relatively cross 13 | compatible as it doesn't rely on msvcrt or fcntl for the locking. 14 | """ 15 | class DatabaseLockHandler(object): 16 | 17 | """ Prepare the file locker. Specify the file to lock and optionally 18 | the maximum timeout and the delay between each attempt to lock. 19 | """ 20 | def __init__(self, file_path, process_id , timeout=10, delay=30): 21 | 22 | self.is_locked = False 23 | self.lockfile = file_path 24 | 25 | self.timeout = timeout 26 | self.delay = delay 27 | self.process_id = process_id 28 | 29 | 30 | 31 | def acquire(self): 32 | """ Acquire the lock, if possible. If the lock is in use, it check again 33 | every `wait` seconds. It does this until it either gets the lock or 34 | exceeds `timeout` number of seconds, in which case it throws 35 | an exception. 36 | """ 37 | start_time = time.time() 38 | while True: 39 | try: 40 | self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR) 41 | if self.process_id: 42 | os.write(self.fd, str(self.process_id)) 43 | else: 44 | os.write(self.fd, str('')) 45 | 46 | break 47 | 48 | except OSError as e: 49 | if e.errno != errno.EEXIST: 50 | time.sleep(self.delay) 51 | 52 | if (time.time() - start_time) >= self.timeout: 53 | time.sleep(self.delay) 54 | 55 | self.is_locked = True 56 | 57 | 58 | def release(self): 59 | """ Get rid of the lock by deleting the lockfile. 60 | When working in a `with` statement, this gets automatically 61 | called at the end. 62 | """ 63 | if self.is_locked: 64 | try: 65 | os.close(self.fd) 66 | except: 67 | pass 68 | 69 | 70 | os.unlink(self.lockfile) 71 | self.is_locked = False 72 | 73 | ''' 74 | Check is process alive or dead 75 | 76 | @return: Boolean 77 | ''' 78 | def isProcessLockFileIsDead(self): 79 | """ 80 | Retrieve Process id of previously ran/is running process 81 | and check if this process is still running 82 | if process is still running returns True else return False 83 | pointing file as dead 84 | 85 | """ 86 | if os.path.isfile(self.lockfile): 87 | lock_file = open(self.lockfile, 'r+') 88 | oldprocess_id = lock_file.readline() 89 | lock_file.close() 90 | 91 | # If process Exists then returns False else True 92 | if oldprocess_id != '' and oldprocess_id is not None: 93 | return self.check_pid(int(oldprocess_id)) 94 | else: 95 | try: 96 | os.remove(self.lock_file) 97 | except: 98 | pass 99 | return False 100 | else: 101 | try: 102 | os.remove(self.lock_file) 103 | except: 104 | pass 105 | return False 106 | ''' 107 | Check For the existence of a unix pid. 108 | 109 | @param pid: Process Id To be checked 110 | 111 | @return: Boolean 112 | ''' 113 | def check_pid(self,pid): 114 | """ 115 | Return process status of a given process 116 | @param pid: process id 117 | 118 | @return Boolean 119 | """ 120 | try: 121 | #this line only check is process alive or not 122 | os.kill(int(pid), 0) 123 | except OSError: 124 | return True 125 | else: 126 | return False 127 | 128 | def isLockFileExists(self): 129 | 130 | return os.path.isfile(self.lockfile) -------------------------------------------------------------------------------- /tests/TestCases/RequiredsCreationTestCase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | 9 | # built-in libraries 10 | import unittest 11 | import os 12 | import sys 13 | 14 | # Custom libraries 15 | 16 | from AllFixture.RequiredsCreationFixture import RequiredsCreationFixture 17 | 18 | import ExpectedResults as ExpectedResults 19 | import FailedMessages as FailedMessages 20 | 21 | import AllFixture.helper as helper 22 | sys.path.append(helper.setImportBaseBath()) 23 | 24 | import Main 25 | 26 | 27 | class RequiredsCreationTestCase(object): 28 | 29 | 30 | def __init__(self): 31 | self.App = Main.Main() 32 | self.requireds_creation_fixture = RequiredsCreationFixture() 33 | pass 34 | 35 | def is_report_dir_exists(self): 36 | """ 37 | Is Report Dir Exists 38 | 39 | @return: @return: List 40 | """ 41 | print('is report file exists..........!') 42 | 43 | self.requireds_creation_fixture.createDirsAndFiles() 44 | 45 | if os.path.isdir(self.App.Fixity.Configuration.getReportsPath()): 46 | flag = True 47 | else: 48 | flag = False 49 | 50 | self.requireds_creation_fixture.removeDirsAndFiles() 51 | print("---------------------------------------------------------------------\n") 52 | return [flag, ExpectedResults.RequiredsCreationTestCaseExpectedResult['all'], FailedMessages.RequiredsCreationTestCaseFailMessages['is_report_dir_exists']] 53 | 54 | def is_history_dir_exists(self): 55 | """ 56 | Is History Dir Exists 57 | 58 | @return: @return: List 59 | """ 60 | print('is history file exists..........!') 61 | 62 | self.requireds_creation_fixture.createDirsAndFiles() 63 | if os.path.isdir(self.App.Fixity.Configuration.getHistoryPath()): 64 | flag = True 65 | else: 66 | flag = False 67 | 68 | self.requireds_creation_fixture.removeDirsAndFiles() 69 | print("---------------------------------------------------------------------\n") 70 | return [flag, ExpectedResults.RequiredsCreationTestCaseExpectedResult['all'], FailedMessages.RequiredsCreationTestCaseFailMessages['is_history_dir_exists']] 71 | 72 | def is_schedules_dir_exists(self): 73 | """ 74 | Is Schedules Dir Exists 75 | 76 | @return: @return: List 77 | """ 78 | print('is schedules file exists..........!') 79 | 80 | self.requireds_creation_fixture.createDirsAndFiles() 81 | if os.path.isdir(self.App.Fixity.Configuration.getSchedulesPath()): 82 | flag = True 83 | else: 84 | flag = False 85 | 86 | self.requireds_creation_fixture.removeDirsAndFiles() 87 | print("---------------------------------------------------------------------\n") 88 | return [flag, ExpectedResults.RequiredsCreationTestCaseExpectedResult['all'], FailedMessages.RequiredsCreationTestCaseFailMessages['is_schedules_dir_exists']] 89 | 90 | def is_config_file_exists(self): 91 | """ 92 | Is Config File Exist 93 | 94 | @return: @return: List 95 | """ 96 | print('is config file exists..........!') 97 | 98 | self.requireds_creation_fixture.createDirsAndFiles() 99 | if os.path.isfile(self.App.Fixity.Configuration.getConfig_file_path()): 100 | flag = True 101 | else: 102 | flag = False 103 | 104 | self.requireds_creation_fixture.removeDirsAndFiles() 105 | print("---------------------------------------------------------------------\n") 106 | return [flag, ExpectedResults.RequiredsCreationTestCaseExpectedResult['all'], FailedMessages.RequiredsCreationTestCaseFailMessages['is_config_file_exists']] 107 | 108 | def is_database_file_exists(self): 109 | """ 110 | Is Database File Exists 111 | 112 | @return: @return: List 113 | """ 114 | print('is database file exists..........!') 115 | 116 | self.requireds_creation_fixture.createDirsAndFiles() 117 | if os.path.isfile(self.App.Fixity.Configuration.getDatabaseFilePath()): 118 | flag = True 119 | else: 120 | flag = False 121 | 122 | self.requireds_creation_fixture.removeDirsAndFiles() 123 | print("---------------------------------------------------------------------\n") 124 | return [flag, ExpectedResults.RequiredsCreationTestCaseExpectedResult['all'], FailedMessages.RequiredsCreationTestCaseFailMessages['is_database_file_exists']] 125 | 126 | def is_debug_files_exists(self): 127 | """ 128 | Is Debug File Exists 129 | 130 | @return: List 131 | """ 132 | 133 | print('is debug file exists..........!') 134 | 135 | self.requireds_creation_fixture.createDirsAndFiles() 136 | if os.path.isfile(self.App.Fixity.Configuration.getDebugFilePath()): 137 | flag = True 138 | else: 139 | flag = False 140 | 141 | self.requireds_creation_fixture.removeDirsAndFiles() 142 | print("---------------------------------------------------------------------\n") 143 | return [flag, ExpectedResults.RequiredsCreationTestCaseExpectedResult['all'], FailedMessages.RequiredsCreationTestCaseFailMessages['is_debug_files_exists']] -------------------------------------------------------------------------------- /GUI/ChangeNameGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | from GUI import GUILibraries 8 | from Core import SharedApp 9 | 10 | 11 | # Class to manage the the Name of the project, ChangeName class manages the action of name changing and also updating the scheduler and other information changed ''' 12 | 13 | class ChangeNameGUI(GUILibraries.QDialog ): 14 | 15 | # Contstructor''' 16 | def __init__(self, parent_win): 17 | super(ChangeNameGUI,self).__init__(parent_win) 18 | self.Fixity = SharedApp.SharedApp.App 19 | self.parent_win = parent_win 20 | 21 | self.setWindowModality(GUILibraries.Qt.WindowModal) 22 | self.setWindowTitle('Change Project Name') 23 | self.parent_win.setWindowTitle('Change Project Name') 24 | self.setWindowIcon(GUILibraries.QIcon(r''+(str((self.Fixity.Configuration.getLogoSignSmall()))))) 25 | self.change_name_layout = GUILibraries.QVBoxLayout() 26 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 27 | 28 | # Distructor''' 29 | def destroyChangeName(self): 30 | del self 31 | 32 | 33 | # QDailog Reject Tigger over writen''' 34 | def reject(self): 35 | 36 | try:self.Fixity = SharedApp.SharedApp.App 37 | except:pass 38 | 39 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 40 | super(ChangeNameGUI,self).reject() 41 | 42 | 43 | 44 | # Show this Dialog''' 45 | def ShowDialog(self): 46 | self.show() 47 | self.exec_() 48 | 49 | def destroy(self): 50 | del self 51 | 52 | # Set Layout ''' 53 | def SetLayout(self, layout): 54 | self.change_name_layout = layout 55 | 56 | # Set Layout ''' 57 | def GetLayout(self): 58 | return self.change_name_layout 59 | 60 | # Set Window Layout''' 61 | def SetWindowLayout(self): 62 | self.setLayout(self.change_name_layout) 63 | 64 | # All design Management Done in here got the Change Name 65 | def SetDesgin(self): 66 | 67 | isEnable = True 68 | project_list = self.Fixity.getProjectList() 69 | if len(project_list) <= 0: 70 | isEnable = False 71 | project_list.append('Create & Save Project') 72 | self.GetLayout().addStrut(200) 73 | self.projects = GUILibraries.QComboBox() 74 | self.projects.addItems(project_list) 75 | 76 | self.GetLayout().addWidget(self.projects) 77 | self.change_name_field =GUILibraries.QLineEdit() 78 | self.set_information =GUILibraries.QPushButton("Save && Close") 79 | 80 | self.cancel =GUILibraries.QPushButton("Close Without Saving") 81 | 82 | self.change_name_field.setPlaceholderText("Add New Name") 83 | 84 | self.GetLayout().addWidget(self.change_name_field) 85 | self.GetLayout().addWidget(self.set_information) 86 | 87 | self.GetLayout().addWidget(self.cancel) 88 | 89 | self.set_information.clicked.connect(self.Save) 90 | 91 | self.cancel.clicked.connect(self.Cancel) 92 | self.projects.currentIndexChanged .connect(self.project_changed) 93 | if not isEnable: 94 | self.set_information.setDisabled(True) 95 | self.change_name_field.setDisabled(True) 96 | self.projects.setDisabled(True) 97 | 98 | self.SetWindowLayout() 99 | self.project_changed() 100 | 101 | def Save(self): 102 | 103 | if self.change_name_field.text() == '' and self.change_name_field.text() is None: 104 | self.notification.showError(self, "Failure", GUILibraries.messages['no_project_selected']) 105 | return 106 | 107 | selected_project = self.projects.currentText() 108 | is_project_name_valid = self.Fixity.Validation.ValidateProjectName(self.change_name_field.text()) 109 | 110 | if not is_project_name_valid: 111 | self.notification.showError(self, "Failure", str(GUILibraries.messages['in_valid_project_name'])) 112 | return 113 | else: 114 | 115 | is_this_name_already_taken = False 116 | 117 | if is_this_name_already_taken: 118 | self.notification.showWarning(self, "Failure", GUILibraries.messages['project_already_selected']) 119 | return 120 | 121 | if False: 122 | self.notification.showInformation(self, "Failure", GUILibraries.messages['problem_proj_name_change']) 123 | return 124 | 125 | new_name = self.change_name_field.text() 126 | 127 | try: 128 | project_exists = self.Fixity.ProjectsList[str(new_name)] 129 | project_exists.getID() 130 | project_exists.getTitle() 131 | self.notification.showInformation(self, "Failure", GUILibraries.messages['in_valid_project_name_detailed']) 132 | return 133 | except: 134 | pass 135 | 136 | project_core = self.Fixity.ProjectsList[selected_project] 137 | flag_name_changed = project_core.changeProjectName(selected_project, new_name) 138 | 139 | if flag_name_changed: 140 | currentRow = self.parent_win.projects.currentRow() 141 | self.notification.showInformation(self, "Success", GUILibraries.messages['project_name_changed']) 142 | self.parent_win.refreshProjectSettings() 143 | self.parent_win.projects.setCurrentRow(currentRow) 144 | self.Cancel() 145 | else: 146 | self.notification.showInformation(self, "Failure", GUILibraries.messages['in_valid_project_name_detailed']) 147 | return 148 | 149 | 150 | def project_changed(self): 151 | project_changed = '' 152 | 153 | ''' 154 | Close the Dialog Box 155 | ''' 156 | def Cancel(self): 157 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 158 | self.destroy() 159 | self.close() 160 | 161 | # Launch Dialog 162 | def LaunchDialog(self): 163 | self.SetDesgin() 164 | self.ShowDialog() -------------------------------------------------------------------------------- /GUI/ApplyFiltersGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan 6 | ''' 7 | 8 | from GUI import GUILibraries 9 | from Core import SharedApp 10 | __author__ = 'Furqan' 11 | 12 | #Class to manage the Filter to be implemented for the files with specific extensions 13 | 14 | class ApplyFiltersGUI(GUILibraries.QDialog): 15 | 16 | ''' 17 | Constructor 18 | ''' 19 | def __init__(self,parent_win): 20 | 21 | GUILibraries.QDialog.__init__(self,parent_win) 22 | self.Fixity = SharedApp.SharedApp.App 23 | 24 | self.parent_win = parent_win 25 | self.setWindowModality(GUILibraries.Qt.WindowModal) 26 | self.parent_win.setWindowTitle('Filter File') 27 | self.setWindowTitle('Filter File') 28 | self.setWindowIcon(GUILibraries.QIcon(r''+(str((self.Fixity.Configuration.getLogoSignSmall()))))) 29 | self.filter_files_layout = GUILibraries.QVBoxLayout() 30 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 31 | 32 | ''' 33 | catch Reject even of the Dialog box 34 | ''' 35 | def reject(self): 36 | 37 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 38 | super(ApplyFiltersGUI,self).reject() 39 | 40 | ''' 41 | Distructor 42 | ''' 43 | def destroy(self): 44 | del self 45 | 46 | ''' 47 | Get Window of this 48 | ''' 49 | def GetWindow(self): 50 | return self.FilterFilesWin 51 | 52 | ''' 53 | Get Window of this 54 | ''' 55 | def ShowDialog(self): 56 | self.show() 57 | self.exec_() 58 | 59 | ''' 60 | Set Layout 61 | ''' 62 | def SetLayout(self, layout): 63 | self.filter_files_layout = layout 64 | 65 | ''' 66 | Set Window Layout 67 | ''' 68 | def SetWindowLayout(self): 69 | self.setLayout(self.filter_files_layout) 70 | 71 | ''' 72 | Get Layout 73 | ''' 74 | def GetLayout(self): 75 | return self.filter_files_layout 76 | 77 | ''' 78 | All design Management Done in Here 79 | ''' 80 | def SetDesgin(self): 81 | 82 | counter = 0 83 | isEnable = True 84 | project_list = self.Fixity.getProjectList() 85 | 86 | if len(project_list) <= 0: 87 | isEnable = False 88 | project_list.append('Create & Save Project') 89 | 90 | self.GetLayout().addStrut(200) 91 | self.projects = GUILibraries.QComboBox() 92 | self.projects.addItems(project_list) 93 | self.scheduling_groupBox =GUILibraries.QGroupBox("Scheduling") 94 | self.GetLayout().addWidget(self.projects) 95 | self.filter_field = GUILibraries.QLineEdit() 96 | self.setInformation =GUILibraries.QPushButton("Save && Close") 97 | self.reset = GUILibraries.QPushButton("Reset") 98 | self.cancel = GUILibraries.QPushButton("Close Without Saving") 99 | 100 | self.filter_field.setPlaceholderText("Add Filter") 101 | 102 | self.ignore_hidden_files = GUILibraries.QCheckBox("Ignore Hidden Files") 103 | 104 | self.GetLayout().addWidget(self.ignore_hidden_files) 105 | self.GetLayout().addWidget(self.filter_field) 106 | self.GetLayout().addWidget(self.setInformation) 107 | self.GetLayout().addWidget(self.reset) 108 | self.GetLayout().addWidget(self.cancel) 109 | 110 | if not isEnable: 111 | self.setInformation.setDisabled(True) 112 | self.reset.setDisabled(True) 113 | self.projects.setDisabled(True) 114 | self.filter_field.setDisabled(True) 115 | self.ignore_hidden_files.setDisabled(True) 116 | 117 | self.setInformation.clicked.connect(self.Save) 118 | self.reset.clicked.connect(self.Reset) 119 | self.cancel.clicked.connect(self.Cancel) 120 | 121 | self.projects.currentIndexChanged .connect(self.projectChanged) 122 | self.SetWindowLayout() 123 | self.projectChanged() 124 | 125 | ''' Reset Text of Filters ''' 126 | def Reset(self): 127 | self.filter_field.setText('') 128 | self.ignore_hidden_files.setChecked(False) 129 | 130 | def Save(self): 131 | 132 | selected_project = self.projects.currentText() 133 | filters = self.filter_field.text() 134 | Is_ignore_hidden_files = self.ignore_hidden_files.isChecked() 135 | 136 | if selected_project == '': 137 | self.notification.showError(self, "No Project Selected", GUILibraries.messages['no_project_selected']) 138 | return 139 | 140 | flag = True 141 | project_core = self.Fixity.ProjectRepo.getSingleProject(selected_project) 142 | project_core.applyFilter(filters, Is_ignore_hidden_files) 143 | SharedApp.SharedApp.App = self.Fixity 144 | 145 | if flag is not None: 146 | self.notification.showInformation(self, "Success", GUILibraries.messages['filter_success']) 147 | self.Cancel() 148 | return 149 | else: 150 | self.notification.showError(self, "Failure", GUILibraries.messages['filter_fail']) 151 | 152 | ''' 153 | Triggers on project changed from drop down and sets related information in filters Field 154 | ''' 155 | def projectChanged(self): 156 | selected_project = self.projects.currentText() 157 | project_core = self.Fixity.ProjectRepo.getSingleProject(selected_project) 158 | try: 159 | filters = project_core.getFilters() 160 | ignore_hidden_files = project_core.getIgnore_hidden_file() 161 | 162 | self.filter_field.setText(filters) 163 | 164 | if ignore_hidden_files == 1 or ignore_hidden_files == '1': 165 | self.ignore_hidden_files.setChecked(True) 166 | else: 167 | self.ignore_hidden_files.setChecked(False) 168 | except: 169 | pass 170 | 171 | return 172 | 173 | ''' 174 | Close the Dialog Box 175 | ''' 176 | def Cancel(self): 177 | 178 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 179 | self.destroy() 180 | self.close() 181 | 182 | # Launch Dialog 183 | def LaunchDialog(self): 184 | 185 | self.SetDesgin() 186 | self.ShowDialog() -------------------------------------------------------------------------------- /GUI/PathChangeGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan 6 | ''' 7 | 8 | from GUI import GUILibraries 9 | from Core import SharedApp 10 | 11 | __author__ = 'Furqan' 12 | 13 | # Class to manage the Filter to be implemented for the files with specific extensions 14 | 15 | 16 | class PathChangeGUI(GUILibraries.QDialog): 17 | def __init__(self,parent_win, orignal_path_text ='', change_path_text = '', code = ''): 18 | GUILibraries.QDialog.__init__(self,parent_win) 19 | self.Fixity = SharedApp.SharedApp.App 20 | self.parent_win = parent_win 21 | self.path_change_win = GUILibraries.QDialog(self.parent_win) 22 | self.path_change_win.setWindowModality(GUILibraries.Qt.WindowModal) 23 | self.path_change_win.setWindowTitle('Change Directory') 24 | self.setWindowIcon(GUILibraries.QIcon(r''+(str((self.Fixity.Configuration.getLogoSignSmall()))))) 25 | self.path_change_layout = GUILibraries.QVBoxLayout() 26 | self.orignal_path_text = orignal_path_text 27 | self.change_path_text = change_path_text 28 | self.code = code 29 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 30 | 31 | ''' 32 | Distructor 33 | 34 | @return: None 35 | ''' 36 | def destroy(self): 37 | del self 38 | 39 | ''' 40 | Create Window 41 | 42 | @return: None 43 | ''' 44 | def CreateWindow(self): 45 | self.path_change_win = GUILibraries.QDialog() 46 | 47 | 48 | ''' 49 | Get this Window 50 | 51 | @return: None 52 | ''' 53 | def GetWindow(self): 54 | 55 | return self.path_change_win 56 | 57 | ''' 58 | Show Dialog 59 | 60 | @return: None 61 | ''' 62 | def ShowDialog(self): 63 | self.path_change_win.show() 64 | self.path_change_win.exec_() 65 | ''' 66 | Set Layout 67 | 68 | @return: None 69 | ''' 70 | def SetLayout(self, layout): 71 | self.path_change_layout = layout 72 | 73 | ''' 74 | Get Layout 75 | 76 | @return: None 77 | ''' 78 | def GetLayout(self): 79 | return self.path_change_layout 80 | 81 | ''' 82 | Set Window Layout 83 | 84 | @return: None 85 | ''' 86 | def SetWindowLayout(self): 87 | self.path_change_win.setLayout(self.path_change_layout) 88 | 89 | ''' 90 | Close Click 91 | 92 | @return: None 93 | ''' 94 | def CloseClick(self): 95 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 96 | self.change_the_path_information = False 97 | if self.code >=0: 98 | try: 99 | self.parent_win.dirs_text_fields[(int(self.code) - 1)].setText(str(self.orignal_path_text)) 100 | except: 101 | pass 102 | 103 | self.path_change_win.close() 104 | 105 | ''' 106 | Destroy window Information 107 | 108 | @return: None 109 | ''' 110 | def DestroyEveryThing(self): 111 | self.destroy() 112 | self.path_change_win.close() 113 | 114 | 115 | ''' 116 | All design Management Done in Here 117 | 118 | @return: None 119 | ''' 120 | 121 | def SetDesgin(self): 122 | 123 | self.GetLayout().addStrut(400) 124 | 125 | # Initializing view elements 126 | self.orignalPathLable = GUILibraries.QLabel() 127 | self.changePathToLable = GUILibraries.QLabel() 128 | self.setInformation = GUILibraries.QPushButton("&Orignal Path Information") 129 | self.setInformation = GUILibraries.QPushButton("&Change Path") 130 | self.cancel = GUILibraries.QPushButton("Do Not Change Path") 131 | self.orignalPath = GUILibraries.QTextEdit() 132 | self.changePathTo = GUILibraries.QTextEdit() 133 | 134 | # Set view text 135 | self.orignalPath.setText(self.orignal_path_text) 136 | self.changePathTo.setText(self.change_path_text) 137 | self.orignalPathLable.setText('Change Path From') 138 | self.changePathToLable.setText('To') 139 | self.orignalPath.setDisabled(True) 140 | self.changePathTo.setDisabled(True) 141 | 142 | # Styling 143 | self.orignalPath.setMaximumSize(400, 100) 144 | self.changePathTo.setMaximumSize(400, 100) 145 | self.cancel.setMaximumSize(200, 100) 146 | self.setInformation.setMaximumSize(200, 100) 147 | 148 | # Set Widget to layouts 149 | self.GetLayout().addWidget(self.orignalPathLable) 150 | self.GetLayout().addWidget(self.orignalPath) 151 | self.GetLayout().addWidget(self.changePathToLable) 152 | self.GetLayout().addWidget(self.changePathTo) 153 | self.GetLayout().addWidget(self.setInformation) 154 | self.GetLayout().addWidget(self.cancel) 155 | 156 | # Set triggers 157 | self.setInformation.clicked.connect(self.changeRootDirInfo) 158 | self.cancel.clicked.connect(self.CloseClick) 159 | self.SetWindowLayout() 160 | 161 | #Points out to change the Path of Manifest or not 162 | # 163 | #@return: None 164 | 165 | def changeRootDirInfo(self): 166 | if not GUILibraries.os.path.exists(self.change_path_text): 167 | 168 | self.notification.showWarning(self,'Path Does Not Exist' ,self.change_path_text + GUILibraries.messages['dir_dnt_exists']) 169 | self.change_the_path_information = False 170 | 171 | else: 172 | if (self.orignal_path_text is not None and self.change_path_text is not None) and (self.orignal_path_text != '' and self.change_path_text != ''): 173 | self.change_the_path_information = True 174 | else: 175 | self.change_the_path_information = False 176 | self.path_change_win.close() 177 | 178 | ''' 179 | Close the Dialog Box 180 | ''' 181 | def Cancel(self): 182 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 183 | self.destroy() 184 | self.close() 185 | 186 | # Launch Dialog 187 | def LaunchDialog(self): 188 | 189 | self.SetDesgin() 190 | self.ShowDialog() 191 | #app = GUILibraries.QApplication('asdas') 192 | #w = PathChange(GUILibraries.QDialog()) 193 | #w.SetWindowLayout() 194 | #w.SetDesgin() 195 | #w.ShowDialog() 196 | #app.exec_() 197 | -------------------------------------------------------------------------------- /Core/Debugger.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | 7 | ''' 8 | import os, logging, datetime 9 | from Core import SharedApp 10 | import xml.etree.cElementTree as XmlHanlder 11 | 12 | class Debugger(object): 13 | _instance = None 14 | def __init__(self): 15 | Debugger._instance.setUp() 16 | 17 | @staticmethod 18 | def getInstance(): 19 | if not isinstance(Debugger._instance, Debugger): 20 | Debugger._instance = object.__new__(Debugger) 21 | Debugger._instance.setUp() 22 | return Debugger._instance 23 | 24 | def selfDestruct(self): 25 | del self 26 | 27 | def setUp(self): 28 | 29 | self.Fixity = SharedApp.SharedApp.App 30 | 31 | self.debug_file_path = self.Fixity.Configuration.getDebugFilePath() 32 | 33 | self.config_file_path = self.Fixity.Configuration.getConfig_file_path() 34 | self.loger = logging 35 | 36 | # Create debug file 37 | try: 38 | self.loger.basicConfig(filename=self.debug_file_path, level=logging.DEBUG) 39 | except: 40 | pass 41 | 42 | if self.get() == 'true': 43 | self.is_debugger_on = False 44 | else: 45 | self.is_debugger_on = True 46 | 47 | # 48 | #@param msg 49 | #@param more_information 50 | 51 | def logError(self,msg,more_information = None): 52 | """ 53 | Function to Log Errors 54 | 55 | @param msg: Message to log 56 | @param more_information: More information For Logging 57 | 58 | @return: 59 | """ 60 | 61 | try: 62 | if self.is_debugger_on: 63 | self.addTimeStamp() 64 | self.loger.debug('') 65 | self.loger.debug(msg) 66 | if len(more_information) > 0: 67 | 68 | for key in more_information: 69 | 70 | self.loger.debug(str(key) + '::' + str(more_information[key])+"\n") 71 | 72 | except: 73 | pass 74 | 75 | # 76 | #@param msg 77 | #@param more_information 78 | 79 | def logInfo(self,msg ,more_information = None): 80 | """ 81 | Function to Log Information 82 | 83 | @param msg:Message to log 84 | @param more_information:More information For Logging 85 | 86 | @return: None 87 | """ 88 | try: 89 | if self.is_debugger_on: 90 | self.addTimeStamp() 91 | self.loger.info(msg) 92 | if more_information: 93 | for key in more_information: 94 | self.loger.info(key + '::' + more_information[key]+"\n") 95 | except: 96 | 97 | self.is_debugger_on = False 98 | pass 99 | 100 | #Function to Log Warning 101 | #@param msg Message to log 102 | #@param more_information More information For Logging 103 | 104 | def logWarning(self,msg,more_information = None): 105 | """ 106 | Function to Log Warning 107 | 108 | @param msg:Message to log 109 | @param more_information:More information For Logging 110 | 111 | @return: None 112 | """ 113 | try: 114 | if self.is_debugger_on: 115 | self.addTimeStamp() 116 | self.loger.warning(msg) 117 | if more_information: 118 | for key in more_information: 119 | self.loger.warning(key + '::' + more_information[key]+"\n") 120 | 121 | except: 122 | 123 | self.is_debugger_on = False 124 | pass 125 | 126 | def set(self, status): 127 | """ 128 | Set Debugging Information 129 | 130 | @param status: 131 | @return: 132 | """ 133 | os.remove(self.config_file_path) 134 | fixity = XmlHanlder.Element("Fixity") 135 | 136 | configuration = XmlHanlder.SubElement(fixity, "Configuration") 137 | debugging = XmlHanlder.SubElement(configuration, "debugging") 138 | 139 | debugging.set("status", status) 140 | 141 | xml_obj = XmlHanlder.ElementTree(fixity) 142 | if status == 'true': 143 | self.is_debugger_on = True 144 | else: 145 | self.is_debugger_on = False 146 | return xml_obj.write(self.config_file_path) 147 | 148 | def get(self): 149 | """ 150 | Get Status 151 | @return: int 152 | """ 153 | tree = XmlHanlder.parse(self.config_file_path) 154 | root = tree.getroot() 155 | for child in root: 156 | for child1 in child: 157 | return child1.attrib['status'] 158 | 159 | def getCurrentTime(self): 160 | """ 161 | Get Current Time 162 | 163 | @return: None 164 | """ 165 | return str(datetime.datetime.now()).rpartition('.')[0] 166 | 167 | def addTimeStamp(self): 168 | """ 169 | Add Time Stamp 170 | 171 | @return: None 172 | """ 173 | self.loger.warning('::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::') 174 | self.loger.warning('::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::') 175 | self.loger.warning(str(self.getCurrentTime())) 176 | self.loger.warning('::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::') 177 | self.loger.warning('') 178 | 179 | def LogException(self, message=''): 180 | """ 181 | Log Exception 182 | 183 | @param message: Message of Exception 184 | 185 | @return: None 186 | """ 187 | self.Fixity = SharedApp.SharedApp.App 188 | 189 | ExceptionDetail = {} 190 | try: 191 | ExceptionDetail = self.Fixity.ExceptionHandler.getExceptionDetails() 192 | except: 193 | pass 194 | 195 | # print('========================== Exception Message ======================') 196 | # print(ExceptionDetail) 197 | # print('========================== Exception Message ======================') 198 | 199 | try: 200 | ExceptionDetail['trace_back'] = self.Fixity.ExceptionHandler.getTraceBack() 201 | except: 202 | pass 203 | 204 | self.logError(message, ExceptionDetail) -------------------------------------------------------------------------------- /Core/EmailNotification.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | #@author: Furqan Wasi 4 | 5 | from Core import SharedApp 6 | 7 | import email, datetime, os 8 | from smtplib import * 9 | 10 | 11 | class EmailNotification(object): 12 | 13 | 14 | def __init__(self): 15 | super(EmailNotification, self).__init__() 16 | self.Fixity = SharedApp.SharedApp.App 17 | 18 | def SendEmail(self, recipients, text, attachment, information, project_name=''): 19 | """ 20 | Note that ADDRESS and PASSWORD should be set before use 21 | 22 | Input: root, output (boolean), hash algorithm, QApplication 23 | Output: list of tuples of (hash, path, id) 24 | 25 | @param recipients: All Recipients Address 26 | @param text: Message To be sent in this Email 27 | @param attachment: attachment To be sent in this Email 28 | @param information: Information About Email Configuration 29 | @param projectName: project Name 30 | @param EmailPref: Email Preferences 31 | 32 | @return: Boolean True If Email Send other wise False 33 | """ 34 | 35 | try:self.Fixity = SharedApp.SharedApp.App 36 | except:pass 37 | addr = str(information['email']) 38 | pas = str(information['pass']) 39 | 40 | msg = email.MIMEMultipart.MIMEMultipart() 41 | msg["From"] = addr 42 | msg["To"] = recipients 43 | 44 | if project_name == '' or project_name is None or project_name is 'None': 45 | msg["Subject"] = "Fixity Report: " + str(datetime.datetime.now()).rpartition('.')[0] 46 | 47 | else: 48 | msg["Subject"] = "Fixity Report: " + str(datetime.datetime.now()).rpartition('.')[0] + ' - ' + project_name 49 | 50 | msg.attach(email.MIMEText.MIMEText(text, 'plain')) 51 | part = email.mime.base.MIMEBase('application', "octet-stream") 52 | 53 | if attachment: 54 | part.set_payload(open(attachment, 'rb').read()) 55 | email.Encoders.encode_base64(part) 56 | part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attachment)) 57 | msg.attach(part) 58 | 59 | protocol = str(information['protocol']) 60 | try: 61 | port = int(str(information['port']).strip()) 62 | except: 63 | return False 64 | 65 | try: 66 | if protocol == 'SSL' or protocol == 'ssl': 67 | server = SMTP_SSL(str(information['smtp']), port) 68 | server.ehlo 69 | server.login(addr, pas) 70 | server.sendmail(addr, recipients, msg.as_string()) 71 | print('sending Email....') 72 | return True 73 | if protocol == 'TLS' or protocol == 'tls': 74 | server = SMTP(str(information['smtp']), port) 75 | server.starttls() 76 | server.login(addr, pas) 77 | server.sendmail(addr, recipients, msg.as_string()) 78 | print('sending Email....') 79 | return True 80 | else: 81 | server = SMTP(str(information['smtp']), port) 82 | if pas != "": 83 | server.login(addr, pas) 84 | server.sendmail(addr, recipients, msg.as_string()) 85 | print('sending Email....') 86 | return True 87 | 88 | except (SMTPException, SMTPServerDisconnected, SMTPResponseException, SMTPSenderRefused, SMTPRecipientsRefused, SMTPDataError, SMTPConnectError, SMTPHeloError, SMTPAuthenticationError, Exception ): 89 | 90 | moreInformation= {} 91 | try: 92 | moreInformation ={'SenderEmailAddress::':addr, 'RecipientsEmailAddress':recipients, '::More Detail':'', 'ErrorMsg':str(Exception.message)} 93 | except: 94 | pass 95 | 96 | self.Fixity.logger.LogException(str(moreInformation)) 97 | 98 | return False 99 | 100 | def TestingEmail(self,recipients, text, information): 101 | """ 102 | Testing Email 103 | 104 | @param recipients: All Recipients Address 105 | @param text: Message To be sent in this Email 106 | @param information: SMTP configuration 107 | 108 | @return: Boolean 109 | """ 110 | try:self.Fixity = SharedApp.SharedApp.App 111 | except:pass 112 | 113 | return self.SendEmail(recipients, text, None, information) 114 | 115 | def ReportEmail(self, recipients, attachment, text, information,project_name): 116 | """ 117 | Report Email 118 | 119 | @param recipients: All Recipients Address 120 | @param attachment: attachment To be sent in this Email 121 | @param text: Message To be sent in this Email 122 | @param information: SMTP configuration 123 | @param projectName: project Name 124 | 125 | @return: 126 | """ 127 | try:self.Fixity = SharedApp.SharedApp.App 128 | except:pass 129 | 130 | all_recipients = str(recipients).split(',') 131 | flag = True 132 | for single_recipients in all_recipients: 133 | 134 | if single_recipients.strip() != '' and single_recipients is not None: 135 | if self.SendEmail(single_recipients, text, attachment, information, project_name) and flag is True: 136 | flag = True 137 | else: 138 | flag = False 139 | return flag 140 | 141 | def ErrorEmail(self, recipients, attachment, text, information, project_name): 142 | 143 | """ 144 | Error Email 145 | 146 | @param recipients: All Recipients Address 147 | @param attachment: attachment To be sent in this Email 148 | @param text: Message To be sent in this Email 149 | @param information: SMTP configuration 150 | @param projectName: project Name 151 | 152 | @return: Boolean 153 | """ 154 | try:self.Fixity = SharedApp.SharedApp.App 155 | except:pass 156 | 157 | flag = True 158 | all_recipients = str(recipients).split(',') 159 | for single_recipients in all_recipients: 160 | if single_recipients.strip() != '' and single_recipients is not None: 161 | if self.SendEmail(single_recipients, text, attachment, information, project_name) and flag is True: 162 | flag = True 163 | else: 164 | flag = False 165 | return flag 166 | -------------------------------------------------------------------------------- /GUI/AboutFixityGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | from GUI import GUILibraries 9 | from Core import SharedApp 10 | import GUI.messages as singleMessage 11 | 12 | OS_Info = 'Windows' 13 | 14 | ''' Class to manage the Filter to be implemented for the files with specific extensions ''' 15 | 16 | 17 | class AboutFixityGUI(GUILibraries.QDialog): 18 | 19 | 20 | ''' Class to manage the Filter to be implemented for the files with specific extensions ''' 21 | 22 | '''Contstructor''' 23 | def __init__(self, parent_win): 24 | 25 | GUILibraries.QDialog.__init__(self, parent_win) 26 | self.Fixity = SharedApp.SharedApp.App 27 | 28 | self.setWindowTitle('About Fixity') 29 | 30 | self.parent_win = parent_win 31 | self.setWindowModality(GUILibraries.Qt.WindowModal) 32 | 33 | self.parent_win.setWindowTitle('About Fixity') 34 | singleMessage.version = self.Fixity.Configuration.getApplicationVersion() 35 | 36 | self.setWindowIcon(GUILibraries.QIcon(self.Fixity.Configuration.getLogoSignSmall())) 37 | self.AboutFixityLayout =GUILibraries.QVBoxLayout() 38 | 39 | self.widget = GUILibraries.QWidget(self) 40 | self.pgroup = GUILibraries.QGroupBox() 41 | self.detail_layout = GUILibraries.QVBoxLayout() 42 | 43 | self.description_btn = GUILibraries.QPushButton('Description') 44 | self.author_and_license_btn = GUILibraries.QPushButton('Author and License') 45 | self.contact_btn = GUILibraries.QPushButton('Contact') 46 | self.close_btn = GUILibraries.QPushButton('Close') 47 | 48 | self.about_layout =GUILibraries.QGroupBox() 49 | self.heading = GUILibraries.QTextEdit() 50 | self.content = GUILibraries.QTextEdit() 51 | 52 | self.heading.setReadOnly(True) 53 | self.content.setReadOnly(True) 54 | 55 | self.main = GUILibraries.QHBoxLayout() 56 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 57 | 58 | def destroy(self): 59 | ''' Distructor''' 60 | del self 61 | 62 | def ShowDialog(self): 63 | ''' Show Dialog''' 64 | self.show() 65 | self.exec_() 66 | 67 | def SetLayout(self, layout): 68 | ''' Set Layout''' 69 | self.AboutFixityLayout = layout 70 | 71 | def showDescription(self): 72 | ''' Show Description''' 73 | self.heading.setText(singleMessage.messages['description_heading']) 74 | descriptionText = singleMessage.messages['description_Content'] 75 | 76 | self.content.setText(descriptionText) 77 | self.description_btn.setDisabled(True) 78 | self.author_and_license_btn.setDisabled(False) 79 | self.contact_btn.setDisabled(False) 80 | def showLicense(self): 81 | ''' Show License Information On About Us Page(Trigger in button press)''' 82 | self.heading.setText(singleMessage.messages['License_heading']) 83 | ''' Header Detail ''' 84 | LicenseText = singleMessage.messages['License_Content'] 85 | 86 | self.content.setText(LicenseText) 87 | self.description_btn.setDisabled(False) 88 | self.author_and_license_btn.setDisabled(True) 89 | self.contact_btn.setDisabled(False) 90 | 91 | def showContact(self): 92 | '''Trigger The Show Contact''' 93 | self.heading.setText(singleMessage.messages['Contact_heading']) 94 | ContactText = singleMessage.messages['Contact_Content'] 95 | 96 | self.content.setText(ContactText) 97 | self.description_btn.setDisabled(False) 98 | self.author_and_license_btn.setDisabled(False) 99 | self.contact_btn.setDisabled(True) 100 | 101 | def SetDesgin(self): 102 | ''' All design Management Done in Here''' 103 | try: 104 | self.description_btn.setFixedSize(210, 30) 105 | self.author_and_license_btn.setFixedSize(210, 30) 106 | self.contact_btn.setFixedSize(210, 30) 107 | except: 108 | self.description_btn =GUILibraries.QPushButton('Description') 109 | self.author_and_license_btn =GUILibraries.QPushButton('Author and License') 110 | self.contact_btn =GUILibraries.QPushButton('Contact') 111 | self.close_btn =GUILibraries.QPushButton('Close') 112 | 113 | pic =GUILibraries.QLabel(self) 114 | pic.setGeometry(30, 30, 500, 600) 115 | pic.setFixedSize(400,400) 116 | 117 | '''use full ABSOLUTE path to the image, not relative''' 118 | 119 | pic.setPixmap(GUILibraries.QPixmap(self.Fixity.Configuration.getLogoSignSmall())) 120 | 121 | self.description_btn.clicked.connect(self.showDescription) 122 | self.author_and_license_btn.clicked.connect(self.showLicense) 123 | self.contact_btn.clicked.connect(self.showContact) 124 | self.close_btn.clicked.connect(self.Cancel) 125 | 126 | self.detail_layout.addWidget(self.description_btn) 127 | self.detail_layout.addWidget(self.author_and_license_btn) 128 | self.detail_layout.addWidget(self.contact_btn) 129 | self.detail_layout.addWidget(pic) 130 | self.pgroup.setLayout(self.detail_layout) 131 | 132 | slay =GUILibraries.QVBoxLayout() 133 | if OS_Info == 'Windows': 134 | self.heading.setFixedSize(485,40) 135 | self.content.setFixedSize(485,500) 136 | else: 137 | self.heading.setFixedSize(500,40) 138 | self.content.setFixedSize(500,500) 139 | 140 | slay.addWidget(self.heading) 141 | slay.addWidget(self.content) 142 | self.close_btn.setFixedSize(200,30) 143 | slay.addWidget(self.close_btn) 144 | if OS_Info == 'Windows': 145 | self.about_layout.setFixedSize(495, 600) 146 | else: 147 | self.about_layout.setFixedSize(540, 600) 148 | self.pgroup.setFixedSize(255, 600) 149 | self.main.addWidget(self.pgroup) 150 | self.main.addWidget(self.about_layout) 151 | 152 | self.about_layout.setLayout(slay) 153 | self.setLayout(self.main) 154 | self.showDescription() 155 | 156 | def Cancel(self): 157 | """ 158 | Close the Dialog Box 159 | @return: 160 | """ 161 | 162 | try:self.Fixity = SharedApp.SharedApp.App 163 | except:pass 164 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 165 | self.destroy() 166 | self.close() 167 | 168 | def LaunchDialog(self): 169 | """ 170 | Launch Dialog 171 | 172 | @return: 173 | """ 174 | self.SetDesgin() 175 | self.ShowDialog() 176 | 177 | -------------------------------------------------------------------------------- /GUI/ImportProjGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan 6 | ''' 7 | 8 | import GUILibraries 9 | from Core import SharedApp, ProjectCore 10 | 11 | # Class to manage the Filter to be implemented for the files with specific extensions 12 | 13 | 14 | class ImportProjectGUI(GUILibraries.QDialog): 15 | 16 | '''Constructor ''' 17 | def __init__(self, parent_win): 18 | 19 | GUILibraries.QDialog.__init__(self,parent_win) 20 | self.Fixity = SharedApp.SharedApp.App 21 | self.parent_win = parent_win 22 | self.setWindowModality(GUILibraries.Qt.WindowModal) 23 | self.parent_win.setWindowTitle('Import Project') 24 | self.setWindowTitle('Import Project') 25 | self.setWindowIcon(GUILibraries.QIcon(r''+(str((self.Fixity.Configuration.getLogoSignSmall()))))) 26 | self.import_projects_layout = GUILibraries.QVBoxLayout() 27 | self.project_list_widget = None 28 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 29 | ''' 30 | Distructor 31 | ''' 32 | def destroy(self): 33 | del self 34 | 35 | 36 | ''' 37 | Get Window 38 | ''' 39 | def GetWindow(self): 40 | return self 41 | ''' 42 | Show Dialog 43 | ''' 44 | def ShowDialog(self): 45 | self.show() 46 | self.exec_() 47 | 48 | ''' 49 | Set Layout 50 | ''' 51 | def SetLayout(self, layout): 52 | self.import_projects_layout = layout 53 | 54 | ''' 55 | Set Window Layout 56 | ''' 57 | def SetWindowLayout(self): 58 | self.setLayout(self.import_projects_layout) 59 | 60 | ''' 61 | Get Layout 62 | ''' 63 | def GetLayout(self): 64 | return self.import_projects_layout 65 | 66 | ''' 67 | All design Management Done in Here 68 | ''' 69 | def SetDesgin(self): 70 | try:self.Fixity = SharedApp.SharedApp.App 71 | except:pass 72 | 73 | self.GetLayout().addStrut(200) 74 | self.projects = GUILibraries.QPushButton('Select Project') 75 | 76 | self.project_selected = GUILibraries.QTextEdit() 77 | self.projects.clicked.connect(self.pickDir) 78 | 79 | self.GetLayout().addWidget(self.projects) 80 | self.project_selected = GUILibraries.QLineEdit() 81 | self.set_information = GUILibraries.QPushButton("Import") 82 | self.cancel = GUILibraries.QPushButton("Close Without Saving") 83 | 84 | self.project_selected.setPlaceholderText("Project Path") 85 | 86 | self.GetLayout().addWidget(self.project_selected) 87 | self.GetLayout().addWidget(self.set_information) 88 | 89 | self.GetLayout().addWidget(self.cancel) 90 | 91 | self.set_information.clicked.connect(self.ImportInformation) 92 | 93 | self.cancel.clicked.connect(self.Cancel) 94 | self.project_selected.setDisabled(True) 95 | self.SetWindowLayout() 96 | 97 | ''' 98 | Over ride reject QDialog Trigger 99 | ''' 100 | def reject(self): 101 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 102 | super(ImportProjectGUI,self).reject() 103 | 104 | ''' 105 | Pick Directory 106 | 107 | @return: None 108 | ''' 109 | def pickDir(self): 110 | try:self.Fixity = SharedApp.SharedApp.App 111 | except:pass 112 | 113 | path = self.Fixity.Configuration.getBasePath() 114 | fileInformation = list(GUILibraries.QFileDialog.getOpenFileName(self,"Select File",str(path))) 115 | self.project_selected.setText(str(fileInformation[0])) 116 | 117 | ''' 118 | Reset form 119 | @return: None 120 | ''' 121 | def Reset(self): 122 | self.project_selected.setText('') 123 | 124 | 125 | def ImportInformation(self): 126 | try:self.Fixity = SharedApp.SharedApp.App 127 | except:pass 128 | 129 | project_core = ProjectCore.ProjectCore() 130 | file_path = str(self.project_selected.text()) 131 | 132 | if file_path is None or file_path == '': 133 | return 'select_manifest_file' 134 | 135 | flag_is_a_tsv_file = False 136 | flag_is_a_fxy_file = False 137 | 138 | file_name = str(GUILibraries.os.path.basename(file_path)) 139 | 140 | if '.tsv' in file_name: 141 | flag_is_a_tsv_file = True 142 | 143 | if '.fxy' in file_name: 144 | flag_is_a_fxy_file = True 145 | 146 | if not flag_is_a_fxy_file and not flag_is_a_tsv_file: 147 | self.notification.showError(self, 'Invalid Name', GUILibraries.messages['invalid_file_given']) 148 | return 149 | 150 | QID = GUILibraries.QInputDialog(self) 151 | QID.setWindowModality(GUILibraries.Qt.WindowModal) 152 | name = QID.getText(self, "Project Name", "Name for new Fixity project:", text="New_Project") 153 | 154 | if not name[1]: 155 | self.notification.showError(self, 'Invalid Name', GUILibraries.messages['in_valid_project_name']) 156 | return 157 | 158 | file_name = name[0] 159 | 160 | responseName = self.Fixity.Validation.ValidateProjectName(file_name) 161 | if not responseName: 162 | self.notification.showError(self, 'Invalid Name', GUILibraries.messages['in_valid_project_name']) 163 | return 164 | 165 | Project = self.Fixity.ProjectRepo.getSingleProject(str(file_name)) 166 | 167 | if Project != False: 168 | self.notification.showError(self, 'Invalid Name', GUILibraries.messages['project_already_selected']) 169 | return 170 | 171 | self.setWindowTitle('Importing Project ....') 172 | self.parent_win.setWindowTitle('Importing Project ....') 173 | self.parent_win.togglerMenu(False) 174 | 175 | if project_core.ImportProject(self.project_selected.text(), file_name, flag_is_a_tsv_file, flag_is_a_fxy_file): 176 | self.notification.showInformation(self, 'Project Imported', GUILibraries.messages['project_imported_sccuessfully']) 177 | self.parent_win.refreshProjectSettings() 178 | self.parent_win.toggler(False) 179 | self.Cancel() 180 | else: 181 | self.notification.showError(self, 'Invalid Import File', GUILibraries.messages['invalid_import_file']) 182 | self.parent_win.refreshProjectSettings() 183 | 184 | 185 | ''' 186 | Close the Dialog Box 187 | ''' 188 | def Cancel(self): 189 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 190 | self.destroy() 191 | self.close() 192 | 193 | # Launch Dialog 194 | def LaunchDialog(self): 195 | self.SetDesgin() 196 | self.ShowDialog() 197 | 198 | #app = GUILibraries.QApplication('asdas') 199 | #w = ImportProjectGUI(GUILibraries.QDialog()) 200 | #w.SetWindowLayout() 201 | #w.SetDesgin() 202 | #w.ShowDialog() 203 | #exit(app.exec_()) -------------------------------------------------------------------------------- /Config/Setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | import os, traceback 8 | from Core import SharedApp 9 | import xml.etree.cElementTree as XmlHanlder 10 | 11 | class Setup(object): 12 | 13 | def __init__(self): 14 | self.Fixity = SharedApp.SharedApp.App 15 | self.is_debugger_on = True 16 | self.debug_file_path = self.Fixity.Configuration.getDebugFilePath() 17 | 18 | self.config_file_path = self.Fixity.Configuration.getConfig_file_path() 19 | 20 | def setupApp(self): 21 | self.createDirsAndFiles() 22 | 23 | def createDirsAndFiles(self): 24 | # Create Config file 25 | if not os.path.isfile(self.config_file_path): 26 | try: 27 | status = 'false' 28 | fixity = XmlHanlder.Element("Fixity") 29 | 30 | configuration = XmlHanlder.SubElement(fixity, "Configuration") 31 | debugging = XmlHanlder.SubElement(configuration, "debugging") 32 | 33 | debugging.set("status", status) 34 | 35 | xml_obj = XmlHanlder.ElementTree(fixity) 36 | if status == 'true': 37 | self.is_debugger_on = True 38 | else: 39 | self.is_debugger_on = False 40 | xml_obj.write(self.config_file_path) 41 | 42 | except: 43 | traceback.print_stack() 44 | pass 45 | 46 | if self.Fixity.Configuration.getOsType() == 'linux': 47 | if not os.path.isdir(self.Fixity.Configuration.getLibAgentPath()): 48 | os.makedirs(self.Fixity.Configuration.getLibAgentPath()) 49 | 50 | if not os.path.isdir(self.Fixity.Configuration.getAgentPath()): 51 | try: 52 | os.mkdir(self.Fixity.Configuration.getAgentPath()) 53 | except: 54 | traceback.print_stack() 55 | pass 56 | 57 | if not os.path.isdir(self.Fixity.Configuration.getLibAgentPath()): 58 | try: 59 | os.mkdir(self.Fixity.Configuration.getLibAgentPath()) 60 | except: 61 | traceback.print_stack() 62 | pass 63 | 64 | # create Database file 65 | if not os.path.isfile(self.Fixity.Configuration.getDatabaseFilePath()): 66 | try: 67 | DatabaseFile = open(str(self.Fixity.Configuration.getDatabaseFilePath()), 'w+') 68 | DatabaseFile.close() 69 | except: 70 | traceback.print_stack() 71 | pass 72 | 73 | # Create History directory 74 | if not os.path.isdir(self.Fixity.Configuration.getHistoryPath()): 75 | try: 76 | os.mkdir(self.Fixity.Configuration.getHistoryPath()) 77 | except: 78 | traceback.print_stack() 79 | pass 80 | 81 | # Create Schedules directory 82 | if not os.path.isdir(self.Fixity.Configuration.getSchedulesPath()): 83 | try: 84 | os.mkdir(self.Fixity.Configuration.getSchedulesPath()) 85 | except: 86 | traceback.print_stack() 87 | pass 88 | 89 | # Create Reports directory 90 | if not os.path.isdir(self.Fixity.Configuration.getReportsPath()): 91 | try: 92 | os.mkdir(self.Fixity.Configuration.getReportsPath()) 93 | except: 94 | traceback.print_stack() 95 | pass 96 | 97 | def createTables(self): 98 | 99 | if not self.checkIfTableExistsInDatabase('configuration'): 100 | ''' Create Configuration Table''' 101 | try: 102 | 103 | self.Fixity.Database.sqlQuery('CREATE TABLE "configuration" ( id INTEGER NOT NULL, smtp TEXT, email TEXT, pass TEXT, port INTEGER, protocol TEXT, debugger SMALLINT, "updatedAt" DATETIME, "createdAt" DATETIME, PRIMARY KEY (id) );') 104 | 105 | except: 106 | traceback.print_stack() 107 | pass 108 | 109 | if not self.checkIfTableExistsInDatabase('project'): 110 | ''' Create Project Table''' 111 | try: 112 | self.Fixity.Database.sqlQuery('CREATE TABLE "project" (id INTEGER PRIMARY KEY, versionCurrentID INTEGER, projectRanBefore SMALLINT DEFAULT 0, title VARCHAR(255), durationType INTEGER, runTime TEXT(10), lastDifPaths TEXT NULL DEFAULT NULL, runDayOrMonth VARCHAR(12),selectedAlgo VARCHAR(8),filters TEXT, runWhenOnBattery SMALLINT, ifMissedRunUponRestart SMALLINT, ignoreHiddenFiles NUMERIC, emailOnlyUponWarning SMALLINT, emailAddress TEXT,extraConf TEXT, lastRan DATETIME, updatedAt DATETIME, createdAt DATETIME);') 113 | except: 114 | traceback.print_stack() 115 | pass 116 | 117 | if not self.checkIfTableExistsInDatabase('projectPath'): 118 | ''' Create ProjectPath Table''' 119 | try: 120 | self.Fixity.Database.sqlQuery('CREATE TABLE "projectPath" ( id INTEGER NOT NULL, "projectID" INTEGER NOT NULL, "versionID" INTEGER, path TEXT NOT NULL, "pathID" VARCHAR(15) NOT NULL, "updatedAt" DATETIME,"createdAt"DATETIME, PRIMARY KEY (id), FOREIGN KEY("projectID") REFERENCES project (id), FOREIGN KEY("versionID") REFERENCES versions (id));') 121 | except: 122 | traceback.print_stack() 123 | pass 124 | 125 | if not self.checkIfTableExistsInDatabase('versionDetail'): 126 | ''' Create VersionDetail Table''' 127 | try: 128 | self.Fixity.Database.sqlQuery('CREATE TABLE "versionDetail" (id INTEGER NOT NULL, "versionID" INTEGER NOT NULL, "projectID" INTEGER NOT NULL, "projectPathID" INTEGER NOT NULL, "hashes" TEXT NOT NULL, "path" TEXT NOT NULL, inode TEXT NOT NULL, "updatedAt" DATETIME, "createdAt" DATETIME, PRIMARY KEY (id), FOREIGN KEY("versionID") REFERENCES versions (id), FOREIGN KEY("projectID") REFERENCES project (id), FOREIGN KEY("projectPathID") REFERENCES "projectPath" (id));') 129 | except: 130 | traceback.print_stack() 131 | pass 132 | 133 | if not self.checkIfTableExistsInDatabase('versions'): 134 | ''' Create Versions Table''' 135 | try: 136 | self.Fixity.Database.sqlQuery('CREATE TABLE "versions" (id INTEGER NOT NULL, "versionID" INTEGER NOT NULL, "projectID" INTEGER NOT NULL, "versionType" VARCHAR(10) NOT NULL, name VARCHAR(255) NOT NULL, "updatedAt" DATETIME, "createdAt" DATETIME, PRIMARY KEY (id));') 137 | except: 138 | traceback.print_stack() 139 | pass 140 | 141 | def checkIfTableExistsInDatabase(self, tableName): 142 | try: 143 | return self.Fixity.Database.getOne("SELECT * FROM sqlite_master WHERE name ='" + tableName + "'") 144 | except: 145 | pass -------------------------------------------------------------------------------- /GUI/ChangeAlgorithmGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan 6 | ''' 7 | 8 | from GUI import GUILibraries 9 | from Core import SharedApp, EmailNotification 10 | 11 | 12 | # Class to manage the Algorithm change to be implemented for the files to get Hashes 13 | class ChangeAlgorithmGUI(GUILibraries.QDialog): 14 | 15 | 16 | def __init__(self,parent_win): 17 | GUILibraries.QDialog.__init__(self,parent_win) 18 | 19 | self.parent_win = parent_win 20 | self.setWindowModality(GUILibraries.Qt.WindowModal) 21 | self.Fixity = SharedApp.SharedApp.App 22 | 23 | self.setWindowTitle('Checksum Manager') 24 | self.parent_win.setWindowTitle('Checksum Manager') 25 | self.setWindowIcon(GUILibraries.QIcon(r''+(str((self.Fixity.Configuration.getLogoSignSmall()))))) 26 | self.change_algorithm_layout = GUILibraries.QVBoxLayout() 27 | self.is_method_changed = False 28 | self.is_all_files_confirmed = False 29 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 30 | 31 | # Distructor 32 | def destroy(self): 33 | del self 34 | 35 | # Reject''' 36 | def reject(self): 37 | try:self.Fixity = SharedApp.SharedApp.App 38 | except:pass 39 | 40 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 41 | super(ChangeAlgorithmGUI,self).reject() 42 | 43 | # Create Show Window''' 44 | def ShowDialog(self): 45 | self.show() 46 | self.exec_() 47 | 48 | # Create Show Window''' 49 | def SetLayout(self, layout): 50 | self.change_algorithm_layout = layout 51 | 52 | # Set Layout for Windows''' 53 | def SetWindowLayout(self): 54 | self.setLayout(self.change_algorithm_layout) 55 | 56 | # Get Layout''' 57 | def GetLayout(self): 58 | return self.change_algorithm_layout 59 | 60 | # All design Management Done in Here''' 61 | def SetDesgin(self): 62 | 63 | is_enable = True 64 | all_project_list = self.Fixity.getProjectList() 65 | 66 | if len(all_project_list) <= 0: 67 | is_enable = False 68 | all_project_list.append('Create & Save Project') 69 | 70 | self.GetLayout().addStrut(200) 71 | self.projects = GUILibraries.QComboBox() 72 | self.projects.addItems(all_project_list) 73 | self.methods = GUILibraries.QComboBox() 74 | self.methods.addItems(self.Fixity.Configuration.getCheck_sum_methods()) 75 | self.GetLayout().addWidget(self.projects) 76 | self.set_information = GUILibraries.QPushButton("Save && Close") 77 | self.cancel = GUILibraries.QPushButton("Close Without Saving") 78 | self.GetLayout().addWidget(self.methods) 79 | self.GetLayout().addWidget(self.set_information) 80 | self.GetLayout().addWidget(self.cancel) 81 | 82 | self.set_information.clicked.connect(self.Save) 83 | if not is_enable: 84 | self.methods.setDisabled(True) 85 | self.set_information.setDisabled(True) 86 | self.projects.setDisabled(True) 87 | 88 | self.cancel.clicked.connect(self.Cancel) 89 | self.projects.currentIndexChanged.connect(self.ProjectChanged) 90 | self.SetWindowLayout() 91 | self.ProjectChanged() 92 | selected_project = self.projects.currentText() 93 | project_core = self.Fixity.ProjectRepo.getSingleProject(str(selected_project)) 94 | try: 95 | if project_core.getAlgorithm() == 'md5': 96 | self.methods.setCurrentIndex(1) 97 | else: 98 | self.methods.setCurrentIndex(0) 99 | except: 100 | pass 101 | 102 | def Save(self): 103 | try:self.Fixity = SharedApp.SharedApp.App 104 | except:pass 105 | 106 | msgBox = GUILibraries.QLabel('Loading') 107 | 108 | selected_project = self.projects.currentText() 109 | algo_value_selected = self.methods.currentText() 110 | 111 | if selected_project is None or selected_project == '': 112 | self.notification.showError(self, "Warning", GUILibraries.messages['no_project_selected']) 113 | return 114 | 115 | project_core = self.Fixity.ProjectRepo.getSingleProject(str(selected_project)) 116 | 117 | if project_core.getAlgorithm() == algo_value_selected: 118 | self.notification.showWarning(self, "Failure", GUILibraries.messages['already_using_algorithm']) 119 | return 120 | 121 | last_dif_paths_info = self.Fixity.Database.select(self.Fixity.Database._tableProject,'*',"`id` = '" + str(id) + "' OR `title` like '" + project_core.getTitle() + "'") 122 | try: 123 | project_core.setLast_dif_paths(str(last_dif_paths_info[0]['lastDifPaths'])) 124 | project_core.setFilters(str(last_dif_paths_info[0]['filters'])) 125 | project_core.setAlgorithm(str(last_dif_paths_info[0]['selectedAlgo'])) 126 | #project_core.setProject_ran_before(str(last_dif_paths_info[0]['projectRanBefore'])) 127 | except: 128 | pass 129 | 130 | msgBox.setWindowTitle("Processing ....") 131 | msgBox.setText("Reading Files, please wait ...") 132 | msgBox.show() 133 | 134 | GUILibraries.QCoreApplication.processEvents() 135 | 136 | project_core.SaveSchedule() 137 | result_of_all_file_confirmed = {} 138 | 139 | if not (project_core.getProject_ran_before() == 0 or project_core.getProject_ran_before() == '0' or project_core.getProject_ran_before() == '' or project_core.getProject_ran_before() == 'None' or project_core.getProject_ran_before() is None) : 140 | if project_core.getProject_ran_before() == 1 or project_core.getProject_ran_before() == '1': 141 | result_of_all_file_confirmed = project_core.Run(True) 142 | else: 143 | result_of_all_file_confirmed['file_changed_found'] = False 144 | 145 | else: 146 | result_of_all_file_confirmed['file_changed_found'] = False 147 | 148 | msgBox.close() 149 | 150 | if bool(result_of_all_file_confirmed['file_changed_found']): 151 | self.notification.showWarning(self, 'Failure', GUILibraries.messages['alog_not_changed_mail']) 152 | email_config = self.Fixity.Configuration.getEmailConfiguration() 153 | try: 154 | if email_config['smtp'] != '' and email_config['smtp'] is not None: 155 | email_notification = EmailNotification.EmailNotification() 156 | if project_core.getEmail_address() != '' and project_core.getEmail_address() is not None: 157 | try: 158 | project_name = project_core.getTitle() 159 | except: 160 | project_name = '' 161 | email_notification.ErrorEmail(project_core.getEmail_address(), result_of_all_file_confirmed['report_path'], GUILibraries.messages['alog_not_changed_mail'], email_config, project_name) 162 | except: 163 | self.Fixity.logger.LogException(Exception.message) 164 | pass 165 | return 166 | 167 | update_project_algo = {} 168 | update_project_algo['selectedAlgo'] = algo_value_selected 169 | self.Fixity.Database.update(self.Fixity.Database._tableProject, update_project_algo, "id='" + str(project_core.getID()) + "'") 170 | 171 | project_core.setAlgorithm(algo_value_selected) 172 | 173 | msgBox.setWindowTitle("Processing ....") 174 | msgBox.setText("Changing Algorithm, please wait ...") 175 | msgBox.show() 176 | 177 | GUILibraries.QCoreApplication.processEvents() 178 | project_core.SaveSchedule() 179 | 180 | if project_core.getProject_ran_before() == 1: 181 | project_core.Run(False, False, True) 182 | 183 | msgBox.close() 184 | SharedApp.SharedApp.App = self.Fixity 185 | self.notification.showInformation(self, "Success", selected_project+"'s " + GUILibraries.messages['algorithm_success']) 186 | self.Cancel() 187 | 188 | def ProjectChanged(self): 189 | try:self.Fixity = SharedApp.SharedApp.App 190 | except:pass 191 | 192 | selected_project = self.projects.currentText() 193 | try: 194 | project_core = self.Fixity.ProjectRepo.getSingleProject(str(selected_project)) 195 | 196 | if project_core.getAlgorithm() == 'md5': 197 | self.methods.setCurrentIndex(1) 198 | else: 199 | self.methods.setCurrentIndex(0) 200 | except: 201 | pass 202 | return 203 | 204 | #Close the Dialog Box 205 | def Cancel(self): 206 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 207 | self.destroy() 208 | self.close() 209 | 210 | # Launch Dialog 211 | def LaunchDialog(self): 212 | try:self.Fixity = SharedApp.SharedApp.App 213 | except:pass 214 | self.SetDesgin() 215 | self.ShowDialog() -------------------------------------------------------------------------------- /tests/AllFixture/AlgorithmFixtures.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | 9 | # built-in libraries 10 | import os 11 | import random 12 | import shutil 13 | 14 | # Custom libraries 15 | import Main 16 | from Fixtures import Fixtures 17 | 18 | 19 | class AlgorithmFixtures(Fixtures): 20 | 21 | 22 | def __init__(self): 23 | self.App = Main.Main() 24 | super(AlgorithmFixtures, self).__init__() 25 | self.new_directory = self.unit_test_folder + 'testing_new_dir' + os.sep 26 | self.new_file_name_temp = self.unit_test_folder + 'testing1234.docx' 27 | pass 28 | 29 | def move_file_in_a_directory(self, path_to_be_moved, path_to_be_moved_to): 30 | """ 31 | Move File In a Directory 32 | 33 | @param path_to_be_changed:string Path to be change for testing 34 | @param path_to_be_moved_to:string Path to be change with 35 | """ 36 | 37 | if not os.path.exists(self.new_directory): 38 | os.makedirs(self.new_directory) 39 | 40 | shutil.move(path_to_be_moved, path_to_be_moved_to) 41 | pass 42 | 43 | def create_copy_of_a_file_removed_old_change_name_as_old(self): 44 | """ 45 | Copy , Paste a File , Then Remove old File also change name of the new file as old one 46 | """ 47 | shutil.copy(self.test_file_two, self.new_file_name_temp) 48 | os.remove(self.test_file_two) 49 | self.rename_file(self.new_file_name_temp, self.test_file_two) 50 | 51 | def create_copy_of_a_file_removed_old_change_name_as_old_change_content(self): 52 | """ 53 | Copy , Paste a File , Then Remove old File and change 54 | content of New file also change name of the new file as old one 55 | """ 56 | shutil.copy(self.test_file_two, self.new_file_name_temp) 57 | os.remove(self.test_file_two) 58 | self.rename_file(self.new_file_name_temp, self.test_file_two) 59 | self.new_file(self.test_file_two, 60 | 'Copy , Paste a File , Then Remove old File and change content of' + 61 | ' New file also change name of the new file as old one, Copy ,' + 62 | ' Paste a File , Then Remove old File and change content of New ' + 63 | 'file also change name of the new file as old one') 64 | 65 | def move_file_in_directory_and_change_hash(self, path_to_be_moved, path_to_be_moved_to): 66 | """ 67 | Move File In a Directory and Change hash 68 | 69 | @param path_to_be_changed:string Path to be change for testing 70 | @param path_to_be_moved_to:string Path to be change with 71 | """ 72 | if not os.path.exists(self.new_directory): 73 | 74 | os.makedirs(self.new_directory) 75 | 76 | shutil.move(path_to_be_moved, path_to_be_moved_to) 77 | self.new_file(path_to_be_moved_to, 78 | 'Move file with in a directory and change content , ' + 79 | 'Move file with in a directory and change content.') 80 | pass 81 | 82 | def change_inode(self, path_to_be_changed): 83 | """ 84 | Change Inode 85 | 86 | @param path_to_be_changed:string Path to be change for testing 87 | """ 88 | self.del_file(path_to_be_changed) 89 | self.new_file(path_to_be_changed) 90 | pass 91 | 92 | def change_inode_and_hash(self, path_to_be_changed): 93 | """ 94 | Changed File 95 | 96 | @param path_to_be_changed:string Path to be change for testing 97 | """ 98 | self.del_file(path_to_be_changed) 99 | self.new_file(path_to_be_changed, 'testing the hash and inode changed') 100 | pass 101 | 102 | def change_file_changed_hash_and_path(self, path_to_be_changed): 103 | """ 104 | Change File 105 | 106 | @param path_to_be_changed:string Path to be change for testing 107 | """ 108 | file_obj = open(path_to_be_changed.decode('utf-8'), 'w') 109 | file_obj.write('testing new file ' + str(random.randrange(1, 10000))) 110 | file_obj.close() 111 | 112 | self.rename_file(path_to_be_changed, path_to_be_changed + '_check') 113 | pass 114 | 115 | def load_verification_algorithm_data_for_intersect(self, file_path_given_to_be_created, base_path, content): 116 | """ 117 | Load Verification Algorithm Data For Intersect 118 | 119 | @param file_path_given_to_be_created:string Path to be of file to be created 120 | @param base_path:string Base Path of intersect directory 121 | @param content:string Content for the created files 122 | """ 123 | if not os.path.exists(base_path): 124 | os.makedirs(base_path) 125 | 126 | file_obj1 = open(file_path_given_to_be_created, 'w+') 127 | file_obj1.write(content) 128 | file_obj1.close() 129 | 130 | pass 131 | 132 | def change_directory_path(self): 133 | """ 134 | Changed Directory Path 135 | 136 | @param path_to_be_changed:string Path to be change for testing 137 | """ 138 | last_different_paths = self.unit_test_folder + '||-||Fixity-1,||-||Fixity-2,||-||Fixity-3,||-||Fixity-4,||-||Fixity-5,||-||Fixity-6,||-||Fixity-7' 139 | self.unit_test_folder = self.App.Fixity.Configuration.getBasePath() + 'test2' 140 | 141 | self.test_file_one = self.App.Fixity.Configuration.getBasePath() + 'test2' + os.sep + '1.docx' 142 | self.test_file_two = self.App.Fixity.Configuration.getBasePath() + 'test2' + os.sep + '2.docx' 143 | self.test_file_three = self.App.Fixity.Configuration.getBasePath() + 'test2' + os.sep + '3.docx' 144 | self.test_file_four = self.App.Fixity.Configuration.getBasePath() + 'test2' + os.sep + '4.docx' 145 | 146 | self.load_verification_algorithm_data() 147 | 148 | information = {} 149 | information['path'] = self.unit_test_folder 150 | self.App.Fixity.Database.update(self.App.Fixity.Database._tableProjectPath, information, '1 = 1') 151 | information_update_project = {} 152 | information_update_project['lastDifPaths'] = last_different_paths 153 | self.App.Fixity.Database.update(self.App.Fixity.Database._tableProject, 154 | information_update_project, '1 = 1') 155 | pass 156 | 157 | def change_path_custom(self, new_path): 158 | """ 159 | Change Project Dirs Base Path Given 160 | 161 | @param new_path:string Path to be change for testing 162 | """ 163 | last_different_paths = new_path + '||-||Fixity-1,||-||Fixity-2,||-||Fixity-3,||-||Fixity-4,||-||Fixity-5,||-||Fixity-6,||-||Fixity-7' 164 | information = {} 165 | information['path'] = new_path 166 | self.App.Fixity.Database.update(self.App.Fixity.Database._tableProjectPath 167 | , information, '1 = 1') 168 | 169 | information_update_project = {} 170 | information_update_project['lastDifPaths'] = last_different_paths 171 | self.App.Fixity.Database.update(self.App.Fixity.Database._tableProject, 172 | information_update_project, '1 = 1') 173 | 174 | def rename_file(self, path_to_be_changed, new_path): 175 | """ 176 | Rename File 177 | 178 | @param path_to_be_changed:string Path to be change for testing 179 | @param new_path:string Path to be changed with for testing 180 | """ 181 | 182 | try: 183 | os.rename(path_to_be_changed, new_path) 184 | except: 185 | try: 186 | os.rename(path_to_be_changed.decode('utf-8'), new_path.decode('utf-8')) 187 | except: 188 | os.rename(path_to_be_changed.encode('utf-8'), new_path.encode('utf-8')) 189 | pass 190 | pass 191 | pass 192 | 193 | def change_file(self, path_to_be_changed): 194 | """ 195 | Change File 196 | 197 | @param path_to_be_changed: 198 | @return: 199 | """ 200 | 201 | file_obj = open(path_to_be_changed.decode('utf-8'), 'w') 202 | file_obj.write('testing new file ' + str(random.randrange(1, 10000))) 203 | file_obj.close() 204 | pass 205 | 206 | def del_file(self, path_to_be_deleted): 207 | """ 208 | Delete File 209 | 210 | @param path_to_be_deleted: 211 | @return: 212 | """ 213 | os.remove(path_to_be_deleted.decode('utf-8')) 214 | pass 215 | 216 | def new_file(self, path_to_be_created, content='4 document'): 217 | """ 218 | New File 219 | 220 | @param path_to_be_created: Path to be created 221 | @param content:File Content to be created 222 | 223 | @return: 224 | """ 225 | try: 226 | file_obj = open(path_to_be_created.decode('utf-8'), 'w') 227 | file_obj.write(content) 228 | file_obj.close() 229 | except: 230 | try: 231 | file_obj = open(path_to_be_created.encode('utf-8'), 'w') 232 | file_obj.write(content) 233 | file_obj.close() 234 | except: 235 | file_obj = open(path_to_be_created, 'w') 236 | file_obj.write(content) 237 | file_obj.close() 238 | pass 239 | pass 240 | pass -------------------------------------------------------------------------------- /tests/AllFixture/Fixtures.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | # built-in libraries 9 | import os 10 | import random 11 | import shutil 12 | 13 | # Custom libraries 14 | import sys 15 | import helper 16 | print(helper.setImportBaseBath()) 17 | sys.path.append(helper.setImportBaseBath()) 18 | import Main 19 | 20 | 21 | class Fixtures(object): 22 | 23 | 24 | def __init__(self): 25 | self.App = Main.Main() 26 | 27 | self.unit_test_folder = self.App.Fixity.Configuration.getUnit_test_folder() 28 | self.unit_test_folder_special = self.App.Fixity.Configuration.getUnit_test_folder_special() 29 | 30 | self.project_name = 'New_Project' 31 | self.test_file_one = self.unit_test_folder + '1.docx' 32 | self.test_file_two = self.unit_test_folder + '2.docx' 33 | self.test_file_three = self.unit_test_folder + '3.docx' 34 | self.test_file_four = self.unit_test_folder + '4.txt' 35 | 36 | self.test_file_one_special = self.unit_test_folder_special + '¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ.shpÿ1.docx' 37 | 38 | self.test_file_two_special = self.unit_test_folder_special + '¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ.shpÿ2.docx' 39 | 40 | self.test_file_three_special = self.unit_test_folder_special + '¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ.shpÿ3.docx' 41 | 42 | self.test_file_four_special = self.unit_test_folder_special + 'Unidade_de_C@.#$%onservação4.txt' 43 | 44 | self.test_history_file = self.unit_test_folder + 'history.tsv' 45 | self.attachment = self.unit_test_folder + 'attachment.tsv' 46 | pass 47 | 48 | def delete_testing_data(self): 49 | """ 50 | Delete Testing Data For Unit Test 51 | """ 52 | if os.path.exists(self.unit_test_folder): 53 | shutil.rmtree(self.unit_test_folder) 54 | try: 55 | if os.path.exists(self.unit_test_folder_special.decode('utf-8')): 56 | try: 57 | shutil.rmtree(self.unit_test_folder_special.decode('utf-8')) 58 | except: 59 | pass 60 | except: 61 | if os.path.exists(self.unit_test_folder_special): 62 | shutil.rmtree(self.unit_test_folder_special) 63 | pass 64 | 65 | self.unit_test_folder + 'testing_new_dir' 66 | if os.path.exists(self.unit_test_folder+'test2'): 67 | shutil.rmtree(self.unit_test_folder+'test2') 68 | 69 | if os.path.exists(self.unit_test_folder + 'testing_new_dir'): 70 | shutil.rmtree(self.unit_test_folder + 'testing_new_dir') 71 | 72 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableProject, '1 = 1') 73 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableVersionDetail, '1 = 1') 74 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableProjectPath, '1 = 1') 75 | 76 | 77 | self.unload_verification_algorithm_data() 78 | self.unload_verification_algorithm_data_special() 79 | pass 80 | 81 | def delete_required_dirs(self): 82 | try: 83 | shutil.rmtree(self.App.Fixity.Configuration.getHistoryPath()) 84 | except: 85 | pass 86 | 87 | try: 88 | shutil.rmtree(self.App.Fixity.Configuration.getReportsPath()) 89 | except: 90 | pass 91 | 92 | try: 93 | shutil.rmtree(self.App.Fixity.Configuration.getSchedulesPath()) 94 | except: 95 | pass 96 | 97 | try: 98 | os.remove(self.App.Fixity.Configuration.getDebugFilePath()) 99 | except: 100 | pass 101 | 102 | try: 103 | os.remove(self.App.Fixity.Configuration.getConfig_file_path()) 104 | except: 105 | pass 106 | 107 | try: 108 | os.remove(self.App.Fixity.Configuration.getDatabaseFilePath()) 109 | shutil.rmtree(self.App.Fixity.Configuration.getDatabaseFilePath()) 110 | except: 111 | pass 112 | 113 | def load_verification_algorithm_data(self): 114 | """ 115 | Load Verification Algorithm Data For Unit Test 116 | """ 117 | if os.path.exists(self.unit_test_folder): 118 | shutil.rmtree(self.unit_test_folder) 119 | os.makedirs(self.unit_test_folder) 120 | 121 | self.test_file_one = os.path.join(self.unit_test_folder, '1.docx') 122 | self.test_file_two = os.path.join(self.unit_test_folder, '2.docx') 123 | self.test_file_three = os.path.join(self.unit_test_folder, '3.docx') 124 | self.test_file_four = os.path.join(self.unit_test_folder, '4.txt') 125 | 126 | file_obj1 = open(self.test_file_one, 'w+') 127 | file_obj1.write('1 document') 128 | file_obj1.close() 129 | 130 | file_obj1 = open(self.test_file_two, 'w+') 131 | file_obj1.write('2 document') 132 | file_obj1.close() 133 | 134 | file_obj1 = open(self.test_file_three, 'w+') 135 | file_obj1.write('3 document') 136 | file_obj1.close() 137 | 138 | file_obj1 = open(self.test_file_four, 'w+') 139 | file_obj1.write('4 document') 140 | file_obj1.close() 141 | 142 | def load_special_verification_algorithm_data(self): 143 | """ 144 | Load Verification Algorithm Data For Unit Test 145 | """ 146 | if os.path.exists(self.unit_test_folder_special.decode('utf-8')): 147 | shutil.rmtree(self.unit_test_folder_special.decode('utf-8')) 148 | os.makedirs(self.unit_test_folder_special.decode('utf-8')) 149 | 150 | file_obj1 = open(self.test_file_one_special.decode('utf-8'), 'w+') 151 | file_obj1.write('1 document' + str(random.randrange(1, 10000))) 152 | file_obj1.close() 153 | 154 | file_obj1 = open(self.test_file_two_special.decode('utf-8'), 'w+') 155 | file_obj1.write('2 document' + str(random.randrange(1, 10000))) 156 | file_obj1.close() 157 | 158 | file_obj1 = open(self.test_file_three_special.decode('utf-8'), 'w+') 159 | file_obj1.write('3 document' + str(random.randrange(1, 10000))) 160 | file_obj1.close() 161 | 162 | file_obj1 = open(self.test_file_four_special.decode('utf-8'), 'w+') 163 | file_obj1.write('4 document') 164 | file_obj1.close() 165 | 166 | def load_history_file(self): 167 | """ 168 | Load History File For Unit Test 169 | """ 170 | if os.path.exists(self.unit_test_folder): 171 | shutil.rmtree(self.unit_test_folder) 172 | try: 173 | os.makedirs(self.unit_test_folder) 174 | except: 175 | pass 176 | 177 | test_history_file = open(self.test_history_file, 'w+') 178 | history_content = [ 179 | r"d:\python\Fixity Project\test\test\;" + "\n", 180 | "\n" 181 | "99 0 99\n", 182 | "2014-07-02 13:32:56\n", 183 | "||-||1\n", 184 | "sha256\n", 185 | r"de5450da6769fe7dc515439c235d92ca34b2f979e68ed5e97931fd9ad568fbfa d:\python\Fixity Project\test\test\\1.docx 3803196084131072658628" + "\n", 186 | r"83426e9311b5942db5d3f55eb17dd00238f9def3aaa819949bc653bb595e1b08 d:\python\Fixity Project\test\test\\2.docx 3803196084131072658629" + "\n", 187 | r"412eec9d4443bc26ae1e61c373e9768d44babf7d838d61cfd34e59647b88fa74 d:\python\Fixity Project\test\test\\3.docx 3803196084131072658630" + "\n"] 188 | 189 | test_history_file.writelines(history_content) 190 | test_history_file.close() 191 | 192 | def load_attachment(self): 193 | """ 194 | Load Attachments For Unit Test 195 | """ 196 | if os.path.exists(self.unit_test_folder): 197 | shutil.rmtree(self.unit_test_folder) 198 | 199 | os.makedirs(self.unit_test_folder) 200 | 201 | attachment_file_obj = open(self.attachment, 'w+') 202 | attachment_file_obj.write('Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment Testing Attachment ') 203 | attachment_file_obj.close() 204 | 205 | def unload_attachment(self): 206 | if os.path.exists(self.unit_test_folder): 207 | shutil.rmtree(self.unit_test_folder) 208 | 209 | def unload_verification_algorithm_data(self): 210 | """ 211 | Delete Testing Data For Unit Test 212 | """ 213 | 214 | if os.path.exists(self.unit_test_folder): 215 | shutil.rmtree(self.unit_test_folder) 216 | 217 | try: 218 | testing_new_dir = self.App.Fixity.Configuration.getBasePath()+'test3' 219 | if os.path.exists(testing_new_dir): 220 | shutil.rmtree(testing_new_dir) 221 | except: 222 | pass 223 | 224 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableVersionDetail, '1 = 1') 225 | pass 226 | 227 | def unload_verification_algorithm_data_special(self): 228 | """ 229 | Unload Verification Algorithm Data Special For Unit Test 230 | """ 231 | if os.path.exists(self.unit_test_folder_special): 232 | shutil.rmtree(self.unit_test_folder_special) 233 | 234 | self.App.Fixity.Database.delete(self.App.Fixity.Database._tableVersionDetail, '1 = 1') 235 | pass -------------------------------------------------------------------------------- /tests/TestCases/ProjectTestCase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | 9 | # built-in libraries 10 | import unittest 11 | import os 12 | import sys 13 | 14 | # Custom libraries 15 | 16 | from AllFixture.ProjectFixtures import ProjectFixtures 17 | from Core import ProjectCore 18 | from AllFixture.EmailFixtures import EmailFixtures 19 | 20 | import ExpectedResults as ExpectedResults 21 | import FailedMessages as FailedMessages 22 | 23 | import AllFixture.helper as helper 24 | sys.path.append(helper.setImportBaseBath()) 25 | 26 | import Main 27 | 28 | 29 | class ProjectTestCase(object): 30 | 31 | 32 | def __init__(self): 33 | self.App = Main.Main() 34 | self.project_fixtures = ProjectFixtures() 35 | pass 36 | 37 | def run_project(self, project_name): 38 | """ 39 | Create New Project 40 | @param project_name: project name to be ran 41 | @return: 42 | """ 43 | 44 | print('Test Run Project.........!') 45 | self.project_fixtures.load_verification_algorithm_data() 46 | 47 | self.project_fixtures.create_new_project(project_name) 48 | 49 | project_information = self.App.LaunchCLI(project_name, 'test') 50 | try: 51 | self.project_fixtures.delete_testing_data() 52 | except: 53 | pass 54 | 55 | print("---------------------------------------------------------------------\n") 56 | return [project_information['created'], ExpectedResults.ProjectTestCaseExpectedResult['run_project'], FailedMessages.ProjectTestCaseFailMessages['run_project']] 57 | 58 | def delete_project(self, project_name): 59 | """ 60 | Delete Project 61 | 62 | @param project_name: project name to be Deleted 63 | @return List: 64 | """ 65 | print('Test Delete Project.........!') 66 | 67 | self.project_fixtures.create_new_project(project_name) 68 | project_core = self.App.Fixity.ProjectRepo.getSingleProject(project_name) 69 | 70 | deleted_project_id = project_core.getID() 71 | deleted_project_Title = project_core.getTitle() 72 | 73 | project_core.Delete() 74 | 75 | project_core_deleted = self.App.Fixity.ProjectRepo.getSingleProject(deleted_project_Title) 76 | flag = True 77 | try: 78 | project_core_deleted.getID() 79 | 80 | flag = False 81 | except: 82 | pass 83 | 84 | try: 85 | project_core_deleted.getID() 86 | project_core_deleted.getTitle() 87 | flag = False 88 | except: 89 | pass 90 | 91 | result_project = self.App.Fixity.Database.getProjectInfo(deleted_project_Title) 92 | result_project_detail = self.App.Fixity.Database.getVersionDetailsLast(deleted_project_id) 93 | if len(result_project) > 0: 94 | flag = False 95 | 96 | if len(result_project_detail) > 0: 97 | flag = False 98 | 99 | print("---------------------------------------------------------------------\n") 100 | return [flag, ExpectedResults.ProjectTestCaseExpectedResult['delete_project'], FailedMessages.ProjectTestCaseFailMessages['delete_project']] 101 | 102 | def change_project_name(self, project_name, new_project): 103 | """ 104 | Change Project Name 105 | 106 | @param project_name: project name to be Changed 107 | @param new_project: project name to be changed with 108 | """ 109 | 110 | flag = True 111 | print('Test Change Project Name .........!') 112 | self.project_fixtures.create_new_project(project_name) 113 | 114 | project_core = self.App.Fixity.ProjectRepo.getSingleProject(project_name) 115 | project_core.changeProjectName(project_name, new_project) 116 | project_core_new = self.App.Fixity.ProjectRepo.getSingleProject(new_project) 117 | 118 | try: 119 | project_core_new.getID() 120 | project_core_new.getTitle() 121 | except: 122 | flag = False 123 | 124 | try: 125 | self.project_fixtures.delete_testing_data() 126 | except: 127 | pass 128 | 129 | print("---------------------------------------------------------------------\n") 130 | return [flag, ExpectedResults.ProjectTestCaseExpectedResult['change_project_name'], FailedMessages.ProjectTestCaseFailMessages['change_project_name']] 131 | 132 | def save_project(self, project_name): 133 | """ 134 | Save Project 135 | 136 | @param project_name: project name to be Saved 137 | """ 138 | print('Test Save Project .........!') 139 | flag = False 140 | 141 | #try: 142 | self.project_fixtures.create_new_project(project_name) 143 | project_core = self.App.Fixity.ProjectRepo.getSingleProject(project_name) 144 | project_core.Save() 145 | flag = True 146 | #except: 147 | # print(Exception.message) 148 | # flag = False 149 | print(flag) 150 | try: 151 | self.project_fixtures.delete_testing_data() 152 | except: 153 | pass 154 | 155 | print("---------------------------------------------------------------------\n") 156 | return [flag, ExpectedResults.ProjectTestCaseExpectedResult['save_project'], FailedMessages.ProjectTestCaseFailMessages['save_project']] 157 | 158 | def change_algorithm(self, project_name): 159 | """ 160 | Change Algorithm 161 | 162 | @param project_name: project name to be Changed Algorithm 163 | """ 164 | 165 | print('Test Change Project Algorithm .........!') 166 | 167 | algo_value_selected = 'md5' 168 | flag = True 169 | self.project_fixtures.load_verification_algorithm_data() 170 | self.project_fixtures.create_new_project(project_name) 171 | 172 | project_core = self.App.Fixity.ProjectRepo.getSingleProject(project_name) 173 | 174 | result_of_all_file_confirmed = project_core.Run(True) 175 | 176 | if bool(result_of_all_file_confirmed['file_changed_found']): 177 | email_fixtures = EmailFixtures() 178 | self.App.Fixity.Configuration.setEmailConfiguration(email_fixtures.EmailInformation()) 179 | flag = False 180 | 181 | update_project_algo = {} 182 | update_project_algo['selectedAlgo'] = algo_value_selected 183 | self.App.Fixity.Database.update(self.App.Fixity.Database._tableProject, update_project_algo, "id='" + str(project_core.getID()) + "'") 184 | project_core.setAlgorithm(algo_value_selected) 185 | result_of_all_file_confirmed_second = project_core.Run(True, False, True) 186 | 187 | try: 188 | self.project_fixtures.delete_testing_data() 189 | except: 190 | pass 191 | 192 | if bool(result_of_all_file_confirmed_second['file_changed_found']): 193 | flag = False 194 | 195 | print("---------------------------------------------------------------------\n") 196 | 197 | return [flag, ExpectedResults.ProjectTestCaseExpectedResult['change_algorithm'], FailedMessages.ProjectTestCaseFailMessages['change_algorithm']] 198 | 199 | def filters_files(self, selected_project): 200 | """ 201 | Filters Files 202 | 203 | @param selected_project: project name to be filtered 204 | """ 205 | 206 | print('Test Filters Project .........!') 207 | self.project_fixtures.load_verification_algorithm_data() 208 | 209 | self.project_fixtures.create_new_project(selected_project) 210 | 211 | project_core = self.App.Fixity.ProjectRepo.getSingleProject(selected_project) 212 | project_core.applyFilter('', self.project_fixtures.is_ignore_hidden_files) 213 | project_core.Run(False, False, False, 'test') 214 | 215 | project_core.applyFilter(self.project_fixtures.filters, self.project_fixtures.is_ignore_hidden_files) 216 | result_of_run_after_filter = project_core.Run(False, False, False, 'test') 217 | 218 | self.project_fixtures.load_verification_algorithm_data() 219 | 220 | confirmed = result_of_run_after_filter['confirmed'] 221 | missing_file = result_of_run_after_filter['missing_file'] 222 | created = result_of_run_after_filter['created'] 223 | moved = result_of_run_after_filter['moved'] 224 | corrupted_or_changed = result_of_run_after_filter['corrupted_or_changed'] 225 | 226 | try: 227 | self.project_fixtures.delete_testing_data() 228 | except: 229 | pass 230 | 231 | print("---------------------------------------------------------------------\n") 232 | return [{0: confirmed, 1: missing_file, 2: created, 3: moved, 4: corrupted_or_changed}, ExpectedResults.ProjectTestCaseExpectedResult['filters_files'], FailedMessages.ProjectTestCaseFailMessages['filters_files']] 233 | 234 | def import_project(self, project_name): 235 | """ 236 | Import Project 237 | 238 | @param project_name: project name to be import Project 239 | """ 240 | print('Test Import Project .........!') 241 | self.project_fixtures.load_history_file() 242 | flag = True 243 | project_core = ProjectCore.ProjectCore() 244 | response = project_core.ImportProject(self.project_fixtures.test_history_file, project_name, True, False) 245 | project_core = self.App.Fixity.ProjectRepo.getSingleProject(project_name) 246 | 247 | if not response: 248 | return False 249 | 250 | try: 251 | project_core.getID() 252 | project_core.getTitle() 253 | flag = True 254 | except: 255 | flag = False 256 | pass 257 | 258 | try: 259 | self.project_fixtures.delete_testing_data() 260 | except: 261 | pass 262 | 263 | print("---------------------------------------------------------------------\n") 264 | return [flag, ExpectedResults.ProjectTestCaseExpectedResult['import_project'], FailedMessages.ProjectTestCaseFailMessages['run_project']] -------------------------------------------------------------------------------- /GUI/EmailNotificationGUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan 6 | ''' 7 | 8 | from GUI import GUILibraries 9 | from Core import SharedApp 10 | from Core import EmailNotification 11 | __author__ = 'Furqan' 12 | 13 | # Class to manage the Filter to be implemented for the files with specific extensions 14 | 15 | 16 | class EmailNotificationGUI(GUILibraries.QDialog): 17 | def __init__(self,parent_win): 18 | GUILibraries.QDialog.__init__(self,parent_win) 19 | 20 | self.Fixity = SharedApp.SharedApp.App 21 | self.parent_win = parent_win 22 | self.setWindowTitle('Configure Sender Email') 23 | self.setWindowModality(GUILibraries.Qt.WindowModal) 24 | self.parent_win.setWindowTitle('Configure Sender Email') 25 | self.email_notification = EmailNotification.EmailNotification() 26 | self.setWindowIcon(GUILibraries.QIcon(str(self.Fixity.Configuration.getLogoSignSmall()))) 27 | self.email_pref_layout = GUILibraries.QVBoxLayout() 28 | self.notification = GUILibraries.NotificationGUI.NotificationGUI() 29 | 30 | 31 | def reject(self): 32 | try: 33 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 34 | 35 | except: 36 | pass 37 | try: 38 | super(EmailNotificationGUI, self).reject() 39 | except: 40 | pass 41 | #Distructor 42 | 43 | def destroy(self): 44 | del self 45 | 46 | 47 | # 48 | # Show Dialog 49 | # 50 | # @return: None 51 | # 52 | def ShowDialog(self): 53 | self.show() 54 | self.exec_() 55 | 56 | ''' 57 | Set Layout 58 | 59 | @return: None 60 | ''' 61 | def SetLayout(self, layout): 62 | self.email_pref_layout = layout 63 | 64 | ''' 65 | Set layout for windows 66 | 67 | @return: None 68 | ''' 69 | def SetWindowLayout(self): 70 | self.setLayout(self.email_pref_layout) 71 | 72 | ''' 73 | All design Management Done in Here 74 | 75 | @return: None 76 | ''' 77 | def SetDesgin(self): 78 | self.GetLayout().addStrut(200) 79 | self.Fixity.Configuration.fetchEmailConfiguration() 80 | self.email_addr_bar = GUILibraries.QLineEdit() 81 | self.out_going_mail_server = GUILibraries.QLineEdit() 82 | self.port = GUILibraries.QLineEdit() 83 | self.password = GUILibraries.QLineEdit() 84 | self.SSL_protocol = GUILibraries.QRadioButton("SSL Protocols") 85 | self.TLS_protocol = GUILibraries.QRadioButton("TLS Protocols") 86 | self.none_protocol = GUILibraries.QRadioButton("None") 87 | 88 | self.password.setEchoMode(GUILibraries.QLineEdit.Password) 89 | self.set_information = GUILibraries.QPushButton("Save && Close") 90 | self.reset = GUILibraries.QPushButton("Reset") 91 | self.check_email = GUILibraries.QPushButton("Check Credentials") 92 | self.cancel = GUILibraries.QPushButton("Close Without Saving") 93 | self.loader = GUILibraries.QLabel("Sending Email...") 94 | 95 | self.email_addr_bar.setPlaceholderText("email: user@domain.com") 96 | self.password.setPlaceholderText("Password") 97 | self.out_going_mail_server.setPlaceholderText("smtp.gmail.com") 98 | self.port.setPlaceholderText("Port") 99 | 100 | self.email_addr_bar.setMaximumSize(200, 100) 101 | self.password.setMaximumSize(200, 100) 102 | self.reset.setMaximumSize(200, 100) 103 | self.cancel.setMaximumSize(200, 100) 104 | self.set_information.setMaximumSize(200, 100) 105 | self.out_going_mail_server.setMaximumSize(200, 100) 106 | self.port.setMaximumSize(200, 100) 107 | self.check_email.setMaximumSize(200, 100) 108 | 109 | self.SMTP_server_lable = GUILibraries.QLabel('SMTP Server') 110 | self.email_address_lable = GUILibraries.QLabel('Email Address') 111 | self.password_lable = GUILibraries.QLabel('Password') 112 | self.port_lable = GUILibraries.QLabel('Port') 113 | self.encryption_lable = GUILibraries.QLabel('Encryption Method') 114 | 115 | self.GetLayout().addWidget(self.loader) 116 | self.GetLayout().addWidget(self.SMTP_server_lable) 117 | self.GetLayout().addWidget(self.out_going_mail_server) 118 | 119 | self.GetLayout().addWidget(self.email_address_lable) 120 | self.GetLayout().addWidget(self.email_addr_bar) 121 | 122 | self.GetLayout().addWidget(self.password_lable) 123 | self.GetLayout().addWidget(self.password) 124 | 125 | self.GetLayout().addWidget(self.port_lable) 126 | self.GetLayout().addWidget(self.port) 127 | 128 | self.GetLayout().addWidget(self.encryption_lable) 129 | self.GetLayout().addWidget(self.SSL_protocol) 130 | self.GetLayout().addWidget(self.TLS_protocol) 131 | self.GetLayout().addWidget(self.none_protocol) 132 | self.GetLayout().addWidget(self.set_information) 133 | self.GetLayout().addWidget(self.check_email) 134 | self.GetLayout().addWidget(self.reset) 135 | self.GetLayout().addWidget(self.cancel) 136 | 137 | self.loader.hide() 138 | 139 | self.reset.clicked.connect(self.ResetForm) 140 | self.set_information.clicked.connect(self.Save) 141 | self.cancel.clicked.connect(self.CloseClick) 142 | self.check_email.clicked.connect(self.checkIsEmailValid) 143 | self.SSL_protocol.clicked.connect(self.SSL_protocolConif) 144 | self.TLS_protocol.clicked.connect(self.TLS_protocolConif) 145 | self.none_protocol.clicked.connect(self.none_protocolConif) 146 | 147 | 148 | self.SetWindowLayout() 149 | information = self.Fixity.Configuration.getEmailConfiguration() 150 | self.out_going_mail_server.setText('smtp.gmail.com') 151 | self.setInformation(information) 152 | 153 | self.TLS_protocol.setChecked(True) 154 | self.TLS_protocol.click() 155 | try: 156 | if information is not None and len(information) > 0 and information['smtp'] != None: 157 | self.setInformation(information) 158 | except: 159 | pass 160 | 161 | 162 | 163 | def setInformation(self, information): 164 | 165 | email_addr = '' 166 | Pass = '' 167 | port = '' 168 | smtp = '' 169 | protocol = '' 170 | 171 | if information: 172 | if len(information) > 0: 173 | try: 174 | email_addr = information['email'] 175 | Pass = str(information['pass']) 176 | port = str(information['port']) 177 | smtp = str(information['smtp']) 178 | protocol = str(information['protocol']) 179 | except: 180 | pass 181 | self.email_addr_bar.setText(email_addr) 182 | self.password.setText(Pass) 183 | 184 | if smtp is not None and smtp != '': 185 | self.out_going_mail_server.setText(smtp) 186 | else: 187 | self.out_going_mail_server.setText('smtp.gmail.com') 188 | 189 | if protocol == 'SSL': 190 | self.SSL_protocol.setChecked(True) 191 | self.TLS_protocol.setChecked(False) 192 | self.none_protocol.setChecked(False) 193 | 194 | if port is not None and port != '': 195 | self.port.setText(port) 196 | else: 197 | self.port.setText('465') 198 | 199 | elif protocol == 'TLS': 200 | self.TLS_protocol.setChecked(True) 201 | self.SSL_protocol.setChecked(False) 202 | self.none_protocol.setChecked(False) 203 | if port is not None and port != '': 204 | self.port.setText(port) 205 | else: 206 | self.port.setText('587') 207 | else: 208 | self.none_protocol.setChecked(True) 209 | self.TLS_protocol.setChecked(False) 210 | self.SSL_protocol.setChecked(False) 211 | if port is not None and port != '': 212 | self.port.setText(port) 213 | else: 214 | self.port.setText('25') 215 | ''' 216 | Function to Reset Form information 217 | @return: None 218 | ''' 219 | def ResetForm(self): 220 | self.email_addr_bar.setText('') 221 | self.password.setText('') 222 | self.out_going_mail_server.setText('') 223 | self.port.setText('') 224 | 225 | 226 | 227 | ''' 228 | Validation Configuration provided 229 | @param Email: Email Address 230 | @param Pass: password to check 231 | 232 | @return: String Message of success or failure 233 | ''' 234 | def validateInformation(self, Email, Pass): 235 | try:self.Fixity = SharedApp.SharedApp.App 236 | except:pass 237 | 238 | msgEmailValidation = None 239 | # if Pass == '': 240 | # msgEmailValidation = GUILibraries.messages['provide_valid_pass'] 241 | # return msgEmailValidation 242 | if not GUILibraries.re.match(r"[^@]+@[^@]+\.[^@]+", Email): 243 | msgEmailValidation = GUILibraries.messages['provide_valid_email'] 244 | return msgEmailValidation 245 | return True 246 | 247 | ''' 248 | Manage click on close 249 | 250 | @return: None 251 | ''' 252 | def CloseClick(self): 253 | try: 254 | self.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 255 | 256 | except: 257 | pass 258 | self.destroy() 259 | self.close() 260 | 261 | ''' 262 | TSL configuration manager 263 | 264 | @return: None 265 | ''' 266 | def TLS_protocolConif(self): 267 | information = self.getConfigInfo() 268 | try: 269 | port = str(information['port']) 270 | except: 271 | port = '' 272 | pass 273 | 274 | if port is not None and port != '': 275 | self.port.setText(port) 276 | else: 277 | self.port.setText('587') 278 | ''' 279 | SSL configuration manager 280 | 281 | @return: None 282 | ''' 283 | def SSL_protocolConif(self): 284 | information = self.getConfigInfo() 285 | try: 286 | port = str(information['port']) 287 | except: 288 | port = '' 289 | pass 290 | 291 | if port is not None and port != '': 292 | self.port.setText(port) 293 | else: 294 | self.port.setText('465') 295 | 296 | 297 | ''' 298 | No Encryption Manager 299 | 300 | @return: None 301 | ''' 302 | def none_protocolConif(self): 303 | 304 | try:self.Fixity = SharedApp.SharedApp.App 305 | except:pass 306 | 307 | information = self.getConfigInfo() 308 | try: 309 | port = str(information['port']) 310 | except: 311 | port = '' 312 | pass 313 | 314 | if port is not None and port != '': 315 | self.port.setText(port) 316 | else: 317 | self.port.setText('587') 318 | 319 | def destroy(self): 320 | del self 321 | 322 | def checkIsEmailValid(self): 323 | 324 | try:self.Fixity = SharedApp.SharedApp.App 325 | except:pass 326 | 327 | self.loader.show() 328 | GUILibraries.QCoreApplication.processEvents() 329 | Email = self.email_addr_bar.text() 330 | Pass = self.password.text() 331 | port = self.port.text() 332 | out_going_mail_server = self.out_going_mail_server.text() 333 | 334 | if self.SSL_protocol.isChecked(): 335 | protocol = 'SSL' 336 | elif self.TLS_protocol.isChecked(): 337 | protocol = 'TLS' 338 | else: 339 | protocol = 'NONE' 340 | 341 | if self.out_going_mail_server.text() is None or self.out_going_mail_server.text() == '': 342 | self.notification.showWarning(self, 'Error', GUILibraries.messages['invalid_smtp_given']) 343 | self.loader.hide() 344 | return 345 | 346 | if self.port.text() is None or self.port.text() == '': 347 | self.notification.showWarning(self, 'Error', GUILibraries.messages['invalid_port_given']) 348 | self.loader.hide() 349 | return 350 | 351 | if not GUILibraries.re.match(r"[^@]+@[^@]+\.[^@]+", Email): 352 | self.notification.showWarning(self, 'Error', GUILibraries.messages['invalid_email_given']) 353 | self.loader.hide() 354 | return False 355 | 356 | information = {} 357 | information['pass'] = Pass 358 | information['port'] = port 359 | information['smtp'] = out_going_mail_server 360 | information['email'] = Email 361 | information['protocol'] = protocol 362 | 363 | text = GUILibraries.messages['email_test_content'] 364 | 365 | flag = self.email_notification.TestingEmail(Email,text, information) 366 | if flag: 367 | self.notification.showInformation(self, 'check credentials ', GUILibraries.messages['got_testing_email']) 368 | self.loader.hide() 369 | else: 370 | try: 371 | self.notification.showError(self, 'Error', GUILibraries.messages['testing_email_error']) 372 | self.loader.hide() 373 | except: 374 | self.loader.hide() 375 | pass 376 | 377 | 378 | def GetLayout(self): 379 | return self.email_pref_layout 380 | 381 | def Save(self): 382 | 383 | Email = self.email_addr_bar.text() 384 | Pass = self.password.text() 385 | out_going_mail_server = self.out_going_mail_server.text() 386 | port = self.port.text() 387 | if self.SSL_protocol.isChecked(): 388 | protocol = 'SSL' 389 | elif self.TLS_protocol.isChecked(): 390 | protocol = 'TLS' 391 | else: 392 | protocol = 'NONE' 393 | 394 | if self.out_going_mail_server.text() is None or self.out_going_mail_server.text() == '': 395 | self.notification.showWarning(self, 'Error', GUILibraries.messages['invalid_smtp_given']) 396 | return 397 | 398 | if self.port.text() is None or self.port.text() == '': 399 | self.notification.showWarning(self, 'Error', GUILibraries.messages['invalid_port_given']) 400 | return 401 | errorMsg = self.validateInformation(Email, Pass) 402 | 403 | if errorMsg is not True: 404 | self.notification.showError(self,'Error', errorMsg) 405 | return 406 | information = {} 407 | information['smtp'] = out_going_mail_server 408 | information['email'] = Email 409 | information['pass'] = Pass 410 | information['port'] = port 411 | information['protocol'] = protocol 412 | information['debugger'] = 0 413 | information['createdAt'] = self.Fixity.Configuration.getCurrentTime() 414 | information['updatedAt'] = self.Fixity.Configuration.getCurrentTime() 415 | self.Fixity.Configuration.saveEmailConfiguration(information) 416 | self.Fixity.Configuration.setEmailConfiguration(information) 417 | SharedApp.SharedApp.App = self.Fixity 418 | 419 | self.notification.showInformation(self, "Fixity", GUILibraries.messages['email_save_success']) 420 | self.parent_win.toggleEmailFields() 421 | self.Cancel() 422 | def getConfigInfo(self): 423 | getConfigInfo = '' 424 | 425 | 426 | ''' 427 | Close the Dialog Box 428 | ''' 429 | def Cancel(self): 430 | self.parent_win.setWindowTitle("Fixity "+self.Fixity.Configuration.getApplicationVersion()) 431 | self.destroy() 432 | self.close() 433 | 434 | # Launch Dialog 435 | def LaunchDialog(self): 436 | self.SetDesgin() 437 | self.ShowDialog() 438 | -------------------------------------------------------------------------------- /tests/TestSuite.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on JUNE 30, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | 8 | # built-in libraries 9 | import unittest 10 | import os 11 | import sys 12 | 13 | 14 | # Custom libraries 15 | from AllFixture.ProjectFixtures import ProjectFixtures 16 | from TestCases.ProjectTestCase import ProjectTestCase 17 | from TestCases.EmailTestCase import EmailTestCase 18 | from TestCases.AlgorithmTestCase import AlgorithmTestCase 19 | from TestCases.RequiredsCreationTestCase import RequiredsCreationTestCase 20 | import shutil 21 | 22 | base_path = os.getcwd() 23 | base_path = base_path.replace(r'\tests', '') 24 | sys.path.append(base_path+os.sep) 25 | 26 | from AllFixture.Fixtures import Fixtures 27 | import Main 28 | import unittest 29 | 30 | class TestSuite(unittest.TestCase): 31 | 32 | def setUp(self): 33 | """ 34 | Set Up 35 | 36 | @return: None 37 | """ 38 | print('Start Up') 39 | self.Fixtures = Fixtures() 40 | self.ProjectFixtures = ProjectFixtures() 41 | 42 | self.algorithm_test_case = AlgorithmTestCase() 43 | self.project_test_case = ProjectTestCase() 44 | self.email_test_case = EmailTestCase() 45 | self.requireds_creation_test_case = RequiredsCreationTestCase() 46 | self.App = Main.Main() 47 | self.App.Fixity.loadAllProjects() 48 | pass 49 | 50 | def testARunAlgorithmTestCases(self): 51 | """ 52 | Running Algorithm for Verification Test Cases 53 | 54 | @return: None 55 | """ 56 | 57 | print('==================================================================') 58 | print(' Running Algorithm for Verification Test Cases ') 59 | print('==================================================================') 60 | 61 | # Confirmed FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::NO 62 | response_test_confirm_file = self.algorithm_test_case.test_confirm_file() 63 | self.assertEqual(response_test_confirm_file[0], response_test_confirm_file[1],response_test_confirm_file[2]) 64 | 65 | #New FileExists::YES ||SameHashOfFile::NO ||SameFilePath::NO ||SameI-Node::NO 66 | response_test_new_file = self.algorithm_test_case.test_new_file() 67 | self.assertEqual(response_test_new_file[0], 68 | response_test_new_file[1], 69 | response_test_new_file[2]) 70 | 71 | # Moved FileExists::YES ||SameHashOfFile::YES ||SameFilePath::NO ||SameI-Node::YES 72 | response_test_moved_file = self.algorithm_test_case.test_moved_file() 73 | self.assertEqual(response_test_moved_file[0], 74 | response_test_moved_file[1], 75 | response_test_moved_file[2]) 76 | 77 | # Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::YES ||SameI-Node::YES 78 | response_test_change_file = self.algorithm_test_case.test_change_file() 79 | self.assertEqual(response_test_change_file[0], 80 | response_test_change_file[1], 81 | response_test_change_file[2]) 82 | 83 | # Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::NO ||SameI-Node::YES 84 | response_test_change_file_hp = self.algorithm_test_case.test_change_file_changed_hash_and_path() 85 | self.assertEqual(response_test_change_file_hp[0], 86 | response_test_change_file_hp[1], 87 | response_test_change_file_hp[2]) 88 | 89 | # Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::YES ||SameI-Node::NO 90 | response_test_confirm_file_ih = self.algorithm_test_case.test_change_inode_and_hash_file() 91 | self.assertEqual(response_test_confirm_file_ih[0], 92 | response_test_confirm_file_ih[1], 93 | response_test_confirm_file_ih[2]) 94 | 95 | #Confirmed FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 96 | response_test_confirm_file_all = self.algorithm_test_case.test_confirm_if_inode_changed_of_file() 97 | self.assertEqual(response_test_confirm_file_all[0], 98 | response_test_confirm_file_all[1], 99 | response_test_confirm_file_all[2]) 100 | 101 | #Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 102 | response_test_confirm_file_delete = self.algorithm_test_case.test_delete_file() 103 | self.assertEqual(response_test_confirm_file_delete[0], 104 | response_test_confirm_file_delete[1], 105 | response_test_confirm_file_delete[2]) 106 | 107 | ############################################################################################## 108 | # ================================== Special Character Testing ================================ 109 | ############################################################################################## 110 | 111 | #New FileExists::YES ||SameHashOfFile::NO ||SameFilePath::NO ||SameI-Node::NO 112 | response_test_new_file = self.algorithm_test_case.test_new_file_is_special_chars() 113 | self.assertEqual(response_test_new_file[0], 114 | response_test_new_file[1], 115 | response_test_new_file[2]) 116 | 117 | # Moved FileExists::YES ||SameHashOfFile::YES ||SameFilePath::NO ||SameI-Node::YES 118 | response_test_moved_file = self.algorithm_test_case.test_moved_file_is_special_chars() 119 | self.assertEqual(response_test_moved_file[0], 120 | response_test_moved_file[1], 121 | response_test_moved_file[2]) 122 | 123 | # Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::YES ||SameI-Node::YES 124 | response_test_change_file = self.algorithm_test_case.test_change_file_is_special_chars() 125 | self.assertEqual(response_test_change_file[0], 126 | response_test_change_file[1], 127 | response_test_change_file[2]) 128 | 129 | # Confirmed FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::NO 130 | response_test_confirm_file = self.algorithm_test_case.test_confirm_file_is_special_chars() 131 | self.assertEqual(response_test_confirm_file[0], 132 | response_test_confirm_file[1], 133 | response_test_confirm_file[2]) 134 | 135 | #Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::NO ||SameI-Node::YES 136 | response_test_change_file_hp = self.algorithm_test_case.test_change_file_changed_hash_and_path_is_special_chars() 137 | self.assertEqual(response_test_change_file_hp[0], 138 | response_test_change_file_hp[1], 139 | response_test_change_file_hp[2]) 140 | 141 | # Changed FileExists::YES ||SameHashOfFile::NO ||SameFilePath::YES ||SameI-Node::NO 142 | response_test_confirm_file_ih = self.algorithm_test_case.test_change_inode_and_hash_file_is_special_chars() 143 | self.assertEqual(response_test_confirm_file_ih[0], 144 | response_test_confirm_file_ih[1], 145 | response_test_confirm_file_ih[2]) 146 | 147 | # Confirmed FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 148 | response_test_confirm_file_all = self.algorithm_test_case.test_confirm_if_inode_changed_of_file_is_special_chars() 149 | self.assertEqual(response_test_confirm_file_all[0], 150 | response_test_confirm_file_all[1], 151 | response_test_confirm_file_all[2]) 152 | 153 | # Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 154 | response_test_confirm_file_delete = self.algorithm_test_case.test_delete_file_is_special_chars() 155 | self.assertEqual(response_test_confirm_file_delete[0], 156 | response_test_confirm_file_delete[1], 157 | response_test_confirm_file_delete[2]) 158 | 159 | ###################################################################################################### 160 | # Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 161 | response_test_moved_file_to_new_Directory = self.algorithm_test_case.test_moved_file_to_new_directory() 162 | self.assertEqual(response_test_moved_file_to_new_Directory[0], 163 | response_test_moved_file_to_new_Directory[1], 164 | response_test_moved_file_to_new_Directory[2]) 165 | ###################################################################################################### 166 | 167 | # Deleted FileExists::YES ||SameHashOfFile::YES ||SameFilePath::NO ||SameI-Node::YES 168 | response_test_moved_file_to_new_Directory_change_hash = self.algorithm_test_case.test_moved_file_to_new_Directory_change_hash() 169 | self.assertEqual(response_test_moved_file_to_new_Directory_change_hash[0], 170 | response_test_moved_file_to_new_Directory_change_hash[1], 171 | response_test_moved_file_to_new_Directory_change_hash[2]) 172 | 173 | # Deleted FileExists::YES ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::NO 174 | response_test_moved_new_Directory_change_name_as_old = self.algorithm_test_case.test_moved_file_to_new_Directory_change_name_as_old() 175 | self.assertEqual(response_test_moved_new_Directory_change_name_as_old[0], 176 | response_test_moved_new_Directory_change_name_as_old[1], 177 | response_test_moved_new_Directory_change_name_as_old[2]) 178 | # 179 | # Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 180 | response_test_moved_new_Directory_change_name_and_as_old_and_content = self.algorithm_test_case.test_moved_to_new_directory_change_name_as_old_and_content() 181 | self.assertEqual(response_test_moved_new_Directory_change_name_and_as_old_and_content[0], 182 | response_test_moved_new_Directory_change_name_and_as_old_and_content[1], 183 | response_test_moved_new_Directory_change_name_and_as_old_and_content[2]) 184 | 185 | # Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 186 | response_test_change_base_path = self.algorithm_test_case.test_change_base_path() 187 | self.assertEqual(response_test_change_base_path[0], 188 | response_test_change_base_path[1], 189 | response_test_change_base_path[2]) 190 | 191 | # Deleted FileExists::NO ||SameHashOfFile::YES ||SameFilePath::YES ||SameI-Node::YES 192 | response_test_change_base_path = self.algorithm_test_case.test_intersection_of_dir() 193 | self.assertEqual(response_test_change_base_path[0], 194 | response_test_change_base_path[1], 195 | response_test_change_base_path[2]) 196 | 197 | def testBProjectTestCases(self): 198 | """ 199 | Running Projects Operation Test Cases 200 | 201 | @return: None 202 | """ 203 | print('==================================================================') 204 | print(' Running Projects Operation Test Cases') 205 | print('==================================================================') 206 | 207 | # Project Run Unit test 208 | response_test_run_project = self.project_test_case.run_project(self.Fixtures.project_name) 209 | self.assertEqual(response_test_run_project[0], 210 | response_test_run_project[1], response_test_run_project[2]) 211 | 212 | # Save Project Unit test 213 | response_test_save_project = self.project_test_case.save_project(self.Fixtures.project_name) 214 | self.assertEqual(response_test_save_project[0], 215 | response_test_save_project[1], 216 | response_test_save_project[2]) 217 | 218 | # Filter scanned files Unit test 219 | response_test_filters_files = self.project_test_case.filters_files(self.Fixtures.project_name) 220 | self.assertEqual(response_test_filters_files[0], 221 | response_test_filters_files[1], 222 | response_test_filters_files[2]) 223 | 224 | # Project Run Unit test 225 | response_test_delete_project = self.project_test_case.delete_project(self.Fixtures.project_name) 226 | self.assertEqual(response_test_delete_project[0], 227 | response_test_delete_project[1], response_test_delete_project[2]) 228 | 229 | # Import Project Unit test 230 | response_test_import_project = self.project_test_case.import_project('Testing') 231 | self.assertEqual(response_test_import_project[0], 232 | response_test_import_project[1], response_test_import_project[2]) 233 | # Change Algorithm Unit test 234 | response_test_change_algorithm = self.project_test_case.change_algorithm(self.Fixtures.project_name) 235 | self.assertEqual(response_test_change_algorithm[0], 236 | response_test_change_algorithm[1], response_test_change_algorithm[2]) 237 | 238 | # Change Project Name Unit test 239 | response_test_change_project_name = self.project_test_case.change_project_name(self.Fixtures.project_name, 'testing') 240 | self.assertEqual(response_test_change_project_name[0], 241 | response_test_change_project_name[1], response_test_change_project_name[2]) 242 | 243 | def testCEmailNotification(self): 244 | """ 245 | Running Email Notification Test Cases 246 | 247 | @return: None 248 | """ 249 | print('==================================================================') 250 | print(' Running Email Notification Test Cases') 251 | print('==================================================================') 252 | 253 | # Testing Email Unit Test 254 | response_of_email = self.email_test_case.test_testing_email() 255 | self.assertEqual(response_of_email[0], 256 | response_of_email[1], 257 | response_of_email[2]) 258 | 259 | # Error Email Unit Test 260 | response_of_email_error = self.email_test_case.test_Error_email() 261 | self.assertEqual(response_of_email_error[0], 262 | response_of_email_error[1], 263 | response_of_email_error[2]) 264 | 265 | # Attachment Email Unit Test 266 | response_of_email_attachment = self.email_test_case.test_attachment_email() 267 | self.assertEqual(response_of_email_attachment[0], 268 | response_of_email_attachment[1], 269 | response_of_email_attachment[2]) 270 | pass 271 | 272 | def testDRequiredFilesAndDirsCreation(self): 273 | 274 | print('==================================================================') 275 | print(' Running Required Files And Dirs Creation Test Cases') 276 | print('==================================================================') 277 | 278 | # Is Reports Directory Exists 279 | response_of_is_report_dir_exists = self.requireds_creation_test_case.is_report_dir_exists() 280 | self.assertEqual(response_of_is_report_dir_exists[0], 281 | response_of_is_report_dir_exists[1], 282 | response_of_is_report_dir_exists[2]) 283 | 284 | # Is History Directory Exists 285 | response_of_is_history_dir_exists = self.requireds_creation_test_case.is_history_dir_exists() 286 | self.assertEqual(response_of_is_history_dir_exists[0], 287 | response_of_is_history_dir_exists[1], 288 | response_of_is_history_dir_exists[2]) 289 | 290 | # Is Debug File Exists 291 | response_of_is_debug_files_exists = self.requireds_creation_test_case.is_debug_files_exists() 292 | self.assertEqual(response_of_is_debug_files_exists[0], 293 | response_of_is_debug_files_exists[1], 294 | response_of_is_debug_files_exists[2]) 295 | # Is Config File Exists 296 | response_of_is_config_file_exists = self.requireds_creation_test_case.is_config_file_exists() 297 | 298 | self.assertEqual(response_of_is_config_file_exists[0], 299 | response_of_is_config_file_exists[1], 300 | response_of_is_config_file_exists[2]) 301 | 302 | # Is Database File Exists 303 | response_of_is_database_file_exists = self.requireds_creation_test_case.is_database_file_exists() 304 | self.assertEqual(response_of_is_database_file_exists[0], 305 | response_of_is_database_file_exists[1], 306 | response_of_is_database_file_exists[2]) 307 | 308 | # Is Schedulers Directory Exists 309 | response_of_is_schedules_dir_exists = self.requireds_creation_test_case.is_schedules_dir_exists() 310 | self.assertEqual(response_of_is_schedules_dir_exists[0], 311 | response_of_is_schedules_dir_exists[1], 312 | response_of_is_schedules_dir_exists[2]) 313 | pass 314 | 315 | def tearDown(self): 316 | print('Tear Down!') 317 | self.Fixtures.delete_testing_data() 318 | #self.Fixtures.delete_required_dirs() 319 | print('') 320 | pass 321 | 322 | if __name__ == '__main__': 323 | unittest.main() 324 | 325 | -------------------------------------------------------------------------------- /Config/Configuration.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | ''' 3 | Created on May 14, 2014 4 | 5 | @author: Furqan Wasi 6 | ''' 7 | import os, datetime, sys, platform, base64, plistlib 8 | # import crypto 9 | # sys.modules['Crypto'] = crypto 10 | from Crypto.Cipher import AES 11 | if os.name == "nt": 12 | import _winreg 13 | 14 | from Core.SharedApp import SharedApp 15 | 16 | 17 | class Configuration(object): 18 | def __init__(self): 19 | 20 | # Constructor 21 | if os.name == 'posix': 22 | self.OsType = 'linux' 23 | elif os.name == 'nt': 24 | self.OsType = 'Windows' 25 | 26 | elif os.name == 'os2': 27 | self.OsType = 'check' 28 | 29 | self.Fixity = SharedApp.App 30 | self.application_name = 'Fixity' 31 | self.application_version = '0.5.1' 32 | self.change_file = 'Changed File' 33 | self.move_or_renamed_file = 'Moved or Renamed File' 34 | self.confirmed_file = 'Confirmed File' 35 | self.new_file = 'New File' 36 | self.user_home_path = os.path.expanduser('~') 37 | self.MASTER_KEY = "Avps-FixiTy-$QAL135Flp0l210-Long" 38 | 39 | 40 | if self.OsType == 'Windows': 41 | self.base_path = str(os.getcwd())+str(os.sep) 42 | self.reports_path = r''+(os.path.join(self.base_path, 'reports'+str(os.sep))) 43 | self.schedules_path = r''+(os.path.join(self.base_path, 'schedules'+str(os.sep))) 44 | self.history_path = r''+(os.path.join(self.base_path, 'history'+str(os.sep))) 45 | self.bin_path = r''+(os.path.join(self.base_path, 'bin'+str(os.sep))) 46 | self.assets_path = r''+(os.path.join(self.base_path, 'assets'+str(os.sep))) 47 | self.lock_file_path = r''+(os.path.join(self.base_path, 'dblocker.log')) 48 | self.log_file_path = r''+(os.path.join(self.base_path, 'debug.log')) 49 | self.database_file_path = r''+(os.path.join(self.base_path,'Fixity.db')) 50 | self.template_path = r''+(os.path.join(self.assets_path,'template')+str(os.sep)) 51 | self.report_template_path = r''+(os.path.join(self.template_path)+'Report.txt') 52 | self.history_template_path = r''+(os.path.join(self.template_path)+'History.txt') 53 | self.report_email_template_path = r''+(os.path.join(self.template_path)+'ReportEmail.txt') 54 | self.sch_daily_template_path = r''+(os.path.join(self.template_path)+'SchedulerWinDaily.xml') 55 | self.sch_week_template_path = r''+(os.path.join(self.template_path)+'SchedulerWinWeek.xml') 56 | self.sch_month_template_path = r''+(os.path.join(self.template_path)+'SchedulerWinMonth.xml') 57 | 58 | self.sch_daily_template_path_admin = r''+(os.path.join(self.template_path)+'SchedulerWinDailyAdmin.xml') 59 | self.sch_week_template_path_admin = r''+(os.path.join(self.template_path)+'SchedulerWinWeekAdmin.xml') 60 | self.sch_month_template_path_admin = r''+(os.path.join(self.template_path)+'SchedulerWinMonthAdmin.xml') 61 | 62 | self.config_file_path = self.getBasePath()+'conf.xml' 63 | try: 64 | self.avpreserve_img = os.path.join(sys._MEIPASS, 'assets' + (str(os.sep)) +'avpreserve.png') 65 | except: 66 | pass 67 | self.unit_test_folder = self.base_path + 'test'+os.sep 68 | self.unit_test_folder_special = self.base_path + '¿À�?Âà ÄÅÆÇÈÉÊËÌ�?Î�?�?ÑÒÓÔÕÖØÙÚÛÜ�?Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ ÿ' + os.sep 69 | 70 | else: 71 | 72 | self.lib_agent_path = str(self.user_home_path)+str(os.sep)+"Library"+str(os.sep)+"LaunchAgents"+str(os.sep) 73 | self.agent_path = str(self.user_home_path)+str(os.sep)+"Library" 74 | path_info = str(os.getcwd()).replace(str(os.sep)+'Contents'+str(os.sep)+'Resources', '') 75 | path_info = str(path_info).replace('Fixity.app'+str(os.sep), '') 76 | path_info = str(path_info).replace('Fixity.app', '') 77 | path_info = str(path_info).replace('Main.app', '') 78 | 79 | self.base_path = path_info 80 | 81 | self.fixity_launch_path = str(os.getcwd()).replace(str(os.sep)+'Contents'+str(os.sep)+'Resources','') +str(os.sep)+"Contents"+str(os.sep)+"MacOS"+str(os.sep)+"Fixity" 82 | self.reports_path = r''+(os.path.join(self.base_path, 'reports'+str(os.sep))) 83 | self.schedules_path = r''+(os.path.join(os.getcwd(), 'schedules'+str(os.sep))) 84 | self.config_file_path = r''+(os.path.join(os.getcwd(), 'conf.xml')) 85 | self.history_path = r''+(os.path.join(self.base_path, 'history'+str(os.sep))) 86 | self.bin_path = r''+(os.path.join(self.base_path, 'bin'+str(os.sep))) 87 | self.assets_path = r''+(os.path.join(os.getcwd(), 'assets'+str(os.sep))) 88 | self.lock_file_path = r''+(os.path.join(os.getcwd(), 'dblocker.log')) 89 | 90 | self.log_file_path = r''+(os.path.join(os.getcwd(), 'debug.log')) 91 | 92 | self.database_file_path = r''+(os.path.join(os.getcwd(),'Fixity.db')) 93 | 94 | self.template_path = r''+(os.path.join(self.assets_path,'template')+str(os.sep)) 95 | self.report_template_path = r''+(os.path.join(self.template_path)+'Report.txt') 96 | self.history_template_path = r''+(os.path.join(self.template_path)+'History.txt') 97 | 98 | self.report_email_template_path = r''+(os.path.join(self.template_path)+'ReportEmail.txt') 99 | self.sch_daily_template_path_mac = r''+(os.path.join(self.template_path)+'SchedulerMacDaily.xml') 100 | self.sch_week_template_path_mac = r''+(os.path.join(self.template_path)+'SchedulerMacWeek.xml') 101 | self.sch_month_template_path_mac = r''+(os.path.join(self.template_path)+'SchedulerMacMonth.xml') 102 | 103 | self.avpreserve_img = r''+(os.path.join(self.assets_path) + 'avpreserve.png') 104 | self.unit_test_folder = self.base_path + os.sep + 'test'+os.sep 105 | self.unit_test_folder_special = self.base_path + os.sep + '¿À�?Âà ÄÅÆÇÈÉÊËÌ�?Î�?�?ÑÒÓÔÕÖØÙÚÛÜ�?Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ ÿ' + os.sep 106 | 107 | 108 | 109 | self.check_sum_methods = ['sha256', 'md5'] 110 | self.logo_sign_small = 'logo_sign_small.png' 111 | self.number_of_path_directories = 7 112 | self.number_of_path_email = 7 113 | self.email_configuration = {} 114 | self.week_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] 115 | self.WeekInformation = {"Sunday":0, "Monday":1, "Tuesday":2, "Wednesday":3, "Thursday":4, "Friday":5, "Saturday":6 } 116 | self.time_format = "HH:mm" 117 | self.Months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] 118 | self.is_debugging_on = False 119 | 120 | def getSch_daily_template_path(self): return self.sch_daily_template_path 121 | 122 | def getSch_week_template_path(self): return self.sch_week_template_path 123 | 124 | def getSch_month_template_path(self): return self.sch_month_template_path 125 | 126 | def getSch_daily_template_path_admin(self): return self.sch_daily_template_path_admin 127 | 128 | def getSch_week_template_path_admin(self): return self.sch_week_template_path_admin 129 | 130 | def getSch_month_template_path_admin(self): return self.sch_month_template_path_admin 131 | 132 | def getSch_daily_template_path_mac(self): return self.sch_daily_template_path_mac 133 | 134 | def getSch_week_template_path_mac(self): return self.sch_week_template_path_mac 135 | 136 | def getUnit_test_folder(self): return self.unit_test_folder 137 | 138 | def getUnit_test_folder_special(self): return self.unit_test_folder_special 139 | 140 | def getSch_month_template_path_mac(self): return self.sch_month_template_path_mac 141 | 142 | def getHistoryTemplatePath(self):return self.history_template_path 143 | 144 | def getReportTemplatePath(self):return self.report_template_path 145 | 146 | def getReportEmailTemplatePath(self):return self.report_email_template_path 147 | 148 | def getTemplatePath(self):return self.template_path 149 | 150 | def getLockFilePath(self):return self.lock_file_path 151 | 152 | def getCheck_sum_methods(self):return self.check_sum_methods 153 | 154 | def getMonths(self): return self.Months 155 | 156 | def getWeekInformation(self): return self.WeekInformation 157 | 158 | def getImagesPath(self):return str(self.assets_path) 159 | 160 | def getAvpreserve_img(self):return self.avpreserve_img 161 | 162 | def getBasePath(self):return str(self.base_path) 163 | 164 | def getIs_debugging_on(self):return self.is_debugging_on 165 | 166 | def setIs_debugging_on(self, is_debugging_on):self.is_debugging_on = is_debugging_on 167 | 168 | def getApplicationVersion(self):return str(self.application_version) 169 | def getConfig_file_path(self): 170 | return self.config_file_path 171 | def EncodeInfo(self, string_to_be_encoded): 172 | string_to_be_encoded = str(string_to_be_encoded).strip() 173 | return base64.b16encode(base64.b16encode(string_to_be_encoded)) 174 | 175 | 176 | def getLogoSignSmall(self): 177 | if self.getOsType() == 'Windows': 178 | try: 179 | return os.path.join(sys._MEIPASS, 'assets' + (str(os.sep)) + str(self.logo_sign_small)) 180 | except: 181 | pass 182 | else: 183 | os.path.join(self.assets_path) 184 | return os.path.join(self.assets_path, str(self.logo_sign_small)) 185 | 186 | def getOsType(self):return str(self.OsType) 187 | 188 | def getApplicationName(self): return str(self.application_name) 189 | 190 | def getNumberOfPathDirectories(self):return int(self.number_of_path_directories) 191 | 192 | def getNumberOfEmailField(self):return int(self.number_of_path_email) 193 | 194 | def getWeekDays(self): return self.week_days 195 | 196 | def getTimeFormat(self): return self.time_format 197 | 198 | def getUserHomePath(self): return str(os.path.expanduser('~')) 199 | 200 | def getDebugFilePath(self):return str(self.log_file_path) 201 | 202 | def getDatabaseFilePath(self):return str(self.database_file_path) 203 | 204 | def getReportsPath(self):return str(self.reports_path) 205 | 206 | def getSchedulesPath(self):return str(self.schedules_path) 207 | 208 | def getHistoryPath(self): return str(self.history_path) 209 | 210 | def getBinPath(self): return str(self.bin_path) 211 | 212 | def getAgentPath(self): return self.agent_path 213 | 214 | def getLibAgentPath(self): return self.lib_agent_path 215 | 216 | def getFixityLaunchPath(self): return self.fixity_launch_path 217 | 218 | def getEmailConfiguration(self): 219 | return self.email_configuration 220 | 221 | def fetchEmailConfiguration(self): 222 | information = {} 223 | smtp = "" 224 | if self.getOsType() == 'Windows': 225 | keyval = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" 226 | try: 227 | root_key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, keyval, 0, _winreg.KEY_READ) 228 | [email, regtype] = (_winreg.QueryValueEx(root_key, "fixityEmail")) 229 | [smtp, regtype] = (_winreg.QueryValueEx(root_key, "fixitySMTP")) 230 | [passwrd, regtype] = (_winreg.QueryValueEx(root_key, "fixityPass")) 231 | [port, regtype] = (_winreg.QueryValueEx(root_key, "fixityPort")) 232 | [protocol, regtype] = (_winreg.QueryValueEx(root_key, "fixityProtocol")) 233 | [debugg, regtype] = (_winreg.QueryValueEx(root_key, "fixityDebugger")) 234 | _winreg.CloseKey(root_key) 235 | except WindowsError: 236 | print "No Email credentials setting" 237 | 238 | else: 239 | try: 240 | fileName=os.path.expanduser("~/Library/Preferences/Fixity.plist") 241 | if os.path.exists(fileName): 242 | pl = plistlib.readPlist(fileName) 243 | smtp = pl["smtp"] 244 | email = pl["email"] 245 | passwrd = pl["passwrd"] 246 | port = pl["port"] 247 | protocol = pl["protocol"] 248 | debugg = pl["debugger"] 249 | except IOError: 250 | print "No Email credentials setting" 251 | if smtp != "": 252 | information['smtp'] = smtp 253 | information['email'] = email 254 | information['pass'] = self.decrypt_val(passwrd) 255 | information['port'] = int(port) 256 | information['protocol'] = protocol 257 | information['debugger'] = int(debugg) 258 | self.setEmailConfiguration(information) 259 | return information 260 | 261 | def setEmailConfiguration(self, email_configuration): self.email_configuration = email_configuration 262 | 263 | def saveEmailConfiguration(self, information): 264 | 265 | if self.getOsType() == 'Windows': 266 | keyval = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" 267 | try: 268 | if not os.path.exists(keyval): 269 | _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, keyval) 270 | Registrykey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, keyval, 0, _winreg.KEY_WRITE) 271 | _winreg.SetValueEx(Registrykey, "fixityEmail", 0, _winreg.REG_SZ, information["email"]) 272 | _winreg.SetValueEx(Registrykey, "fixityPass", 0, _winreg.REG_SZ, self.encrypt_val(information["pass"])) 273 | _winreg.SetValueEx(Registrykey, "fixityPort", 0, _winreg.REG_NONE, str(information["port"])) 274 | _winreg.SetValueEx(Registrykey, "fixitySMTP", 0, _winreg.REG_SZ, information["smtp"]) 275 | _winreg.SetValueEx(Registrykey, "fixityProtocol", 0, _winreg.REG_SZ, information["protocol"]) 276 | _winreg.SetValueEx(Registrykey, "fixityDebugger", 0, _winreg.REG_NONE, str(information["debugger"])) 277 | _winreg.CloseKey(Registrykey) 278 | except WindowsError: 279 | print("error in saving email credentials") 280 | else: 281 | try: 282 | pl = dict( 283 | smtp=information["smtp"], 284 | email=information["email"], 285 | passwrd=self.encrypt_val(information["pass"]), 286 | port=information["port"], 287 | protocol=information["protocol"], 288 | debugger=information["debugger"] 289 | ) 290 | fileName = os.path.expanduser("~/Library/Preferences/Fixity.plist") 291 | plistlib.writePlist(pl, fileName) 292 | except IOError: 293 | print("error in saving email credentials") 294 | 295 | def getCurrentTime(self): 296 | 297 | current_date = str(datetime.datetime.now()).split('.') 298 | return current_date[0] 299 | 300 | 301 | def getWindowsInformation(self): 302 | """ 303 | Gets Detail information of Windows 304 | @return: tuple Windows Information 305 | """ 306 | WindowsInformation = {} 307 | try: 308 | major, minor, build, platformType, servicePack = sys.getwindowsversion() 309 | WindowsInformation['major'] = major 310 | WindowsInformation['minor'] = minor 311 | WindowsInformation['build'] = build 312 | 313 | WindowsInformation['platformType'] = platformType 314 | WindowsInformation['servicePack'] = servicePack 315 | windowDetailedName = platform.platform() 316 | self.windowDetailedNameObj = windowDetailedName 317 | WindowsInformation['platform'] = windowDetailedName 318 | windowDetailedName = str(windowDetailedName).split('-') 319 | 320 | if windowDetailedName[0] is not None and (str(windowDetailedName[0]) == 'Windows' or str(windowDetailedName[0]) == 'windows'): 321 | WindowsInformation['isWindows'] =True 322 | else: 323 | WindowsInformation['isWindows'] =False 324 | 325 | if windowDetailedName[1] is not None and (str(windowDetailedName[1]) != ''): 326 | WindowsInformation['WindowsType'] =str(windowDetailedName[1]) 327 | else: 328 | WindowsInformation['WindowsType'] =None 329 | 330 | WindowsInformation['ProcessorInfo'] = platform.processor() 331 | 332 | try: 333 | os.environ["PROGRAMFILES(X86)"] 334 | bits = 64 335 | except: 336 | bits = 32 337 | pass 338 | 339 | WindowsInformation['bitType'] = "Win{0}".format(bits) 340 | except: 341 | 342 | pass 343 | return WindowsInformation 344 | 345 | def getWindowsDetailName(self): 346 | """ 347 | @return: object 348 | """ 349 | 350 | try: 351 | return self.windowDetailedNameObj 352 | except: 353 | return '' 354 | pass 355 | def CleanStringForBreaks(self,StringToBeCleaned): 356 | """ 357 | @param StringToBeCleaned: 358 | 359 | @return: 360 | """ 361 | CleanString = StringToBeCleaned.strip() 362 | try: 363 | CleanString = CleanString.replace('\r\n', '') 364 | CleanString = CleanString.replace('\n', '') 365 | CleanString = CleanString.replace('\r', '') 366 | except: 367 | pass 368 | 369 | return CleanString 370 | 371 | def encrypt_val(self, text): 372 | enc_secret = AES.new(self.MASTER_KEY[:32]) 373 | tag_string = (str(text) + 374 | (AES.block_size - 375 | len(str(text)) % AES.block_size) * "\0") 376 | cipher_text = base64.b64encode(enc_secret.encrypt(tag_string)) 377 | 378 | return cipher_text 379 | 380 | def decrypt_val(self, cipher_text): 381 | dec_secret = AES.new(self.MASTER_KEY[:32]) 382 | raw_decrypted = dec_secret.decrypt(base64.b64decode(cipher_text)) 383 | clear_val = raw_decrypted.rstrip("\0") 384 | return clear_val --------------------------------------------------------------------------------