diff options
-rw-r--r-- | form.ui | 249 | ||||
-rw-r--r-- | mga-advisor.py | 185 |
2 files changed, 434 insertions, 0 deletions
@@ -0,0 +1,249 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Widget</class> + <widget class="QWidget" name="Widget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>814</width> + <height>622</height> + </rect> + </property> + <property name="windowTitle"> + <string>Widget</string> + </property> + <widget class="QWidget" name="verticalLayoutWidget"> + <property name="geometry"> + <rect> + <x>-1</x> + <y>-1</y> + <width>811</width> + <height>601</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Mageia Advisories Editor</string> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="group_type"> + <property name="title"> + <string>Type:</string> + </property> + <widget class="QRadioButton" name="bugfix_rb"> + <property name="geometry"> + <rect> + <x>50</x> + <y>0</y> + <width>99</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Bug fix</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" name="security_rb"> + <property name="geometry"> + <rect> + <x>230</x> + <y>0</y> + <width>99</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Security</string> + </property> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Bug report number</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="bug_le"> + <property name="inputMask"> + <string notr="true"/> + </property> + <property name="placeholderText"> + <string>bug number</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="retrieve_pb"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Retrieve info</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Subject</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="subject_le"> + <property name="placeholderText"> + <string>subject</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Description:</string> + </property> + </widget> + </item> + <item> + <widget class="QTextEdit" name="description_te"> + <property name="documentTitle"> + <string>Drescription</string> + </property> + <property name="lineWrapColumnOrWidth"> + <number>72</number> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QListWidget" name="list_src"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QPushButton" name="add_src_pb"> + <property name="text"> + <string>Add source</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="remove_src_pb"> + <property name="text"> + <string>Remove source</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QListWidget" name="list_ref"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QPushButton" name="add_ref_pb"> + <property name="text"> + <string>Add reference</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="remove_ref_pb"> + <property name="text"> + <string>Remove reference</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QListWidget" name="list_cve"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QPushButton" name="add_cve_pb"> + <property name="text"> + <string>Add CVE</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="remove_cve_pb"> + <property name="text"> + <string>Remove CVE</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <widget class="QPushButton" name="cancel_pb"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="preview_pb"> + <property name="text"> + <string>Preview</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="export_pb"> + <property name="text"> + <string>Export</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/mga-advisor.py b/mga-advisor.py new file mode 100644 index 0000000..4869407 --- /dev/null +++ b/mga-advisor.py @@ -0,0 +1,185 @@ +# This Python file uses the following encoding: utf-8 +import os +from pathlib import Path +import sys +import yaml +import textwrap +import re + +from PySide6.QtWidgets import QApplication, QWidget, QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QComboBox, QTextEdit +from PySide6.QtCore import QFile, QDate, QDir +from PySide6.QtUiTools import QUiLoader + + +class LineDialog(QDialog): + def __init__(self, title, init="", parent=None): + super().__init__(parent) + self.setWindowTitle(title) + self.name_ql = QLineEdit() + self.name_ql.setText(init) + apply_bt = QPushButton("Apply") + layout = QHBoxLayout() + layout.addWidget(self.name_ql) + layout.addWidget(apply_bt) + self.setLayout(layout) + apply_bt.clicked.connect(self.apply) + + def apply(self): + self.accept() + +class SrcDialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle("Add source") + self.name_ql = QLineEdit() + self.release = QComboBox() + self.release.addItems(["9", "8"]) + self.repo = QComboBox() + self.repo.addItems(["core", "nonfree", "tainted"]) + apply_bt = QPushButton("Apply") + layout = QHBoxLayout() + layout.addWidget(self.release) + layout.addWidget(self.repo) + layout.addWidget(self.name_ql) + layout.addWidget(apply_bt) + self.setLayout(layout) + apply_bt.clicked.connect(self.apply) + + def apply(self): + self.accept() + +class Widget(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.load_ui() + self.setWindowTitle("Mageia advisor") + + def load_ui(self): + loader = QUiLoader() + path = Path(__file__).resolve().parent / "form.ui" + ui_file = QFile(path) + ui_file.open(QFile.ReadOnly) + self.ui = loader.load(ui_file, self) + ui_file.close() + self.ui.retrieve_pb.clicked.connect(self.retrieve) + self.ui.add_cve_pb.clicked.connect(self.add_cve) + self.ui.remove_cve_pb.clicked.connect(self.remove_cve) + self.ui.add_src_pb.clicked.connect(self.add_src) + self.ui.remove_src_pb.clicked.connect(self.remove_src) + self.ui.add_ref_pb.clicked.connect(self.add_reference) + self.ui.remove_ref_pb.clicked.connect(self.remove_reference) + self.ui.export_pb.clicked.connect(self.export) + self.ui.cancel_pb.clicked.connect(self.cancel) + self.ui.preview_pb.clicked.connect(self.preview) + self.ui.bug_le.editingFinished.connect(self.valid_number) + + def retrieve(self): + print("Action retrieve") + + def add_src(self): + dl = SrcDialog() + name = dl.exec() + self.ui.list_src.addItem( + " ".join((dl.release.currentText(), + dl.repo.currentText(), + self.sanitize_line(dl.name_ql.text()) + )) + ) + + def remove_src(self): + self.ui.list_src.takeItem(self.ui.list_src.currentRow()) + + def add_reference(self): + dl = LineDialog("Add reference") + dl.exec() + self.ui.list_ref.addItem(self.sanitize_line(dl.name_ql.text())) + + + def remove_reference(self): + self.ui.list_ref.takeItem(self.ui.list_ref.currentRow()) + + def add_cve(self): + init_value = f"CVE-{QDate.currentDate().year()}-" + dl = LineDialog("Add CVE", init=init_value) + dl.exec() + self.ui.list_cve.addItem(self.sanitize_line(dl.name_ql.text())) + + def remove_cve(self): + self.ui.list_cve.takeItem(self.ui.list_cve.currentRow()) + + def adv_text(self): + data = {} + if self.ui.bugfix_rb.isEnabled(): + data['type'] = 'bugfix' + if self.ui.security_rb.isEnabled(): + data['type'] = 'security' + if len(self.ui.description_te.toPlainText()) != 0: + data['description'] = self.ui.description_te.toPlainText() + if self.ui.subject_le.text() != "": + data['subject'] = self.sanitize_line(self.ui.subject_le.text()) + cves = [] + n = 0 + for n in range(0, self.ui.list_cve.count()): + cves.append(self.ui.list_cve.item(n).text()) + if n != 0: + data['CVE'] = cves + srcs = {} + n = 0 + for n in range(0, self.ui.list_src.count()): + release, repo, name = self.ui.list_src.item(n).text().split(" ") + if not release in srcs.keys(): + srcs[release] = {} + srcs[release][repo] = [] + else: + if not repo in srcs[release].keys(): + srcs[release][repo] = [] + srcs[release][repo].append(name) + if n != 0: + data['src'] = srcs + refs = [] + n = 0 + for n in range(0, self.ui.list_ref.count()): + refs.append(self.ui.list_ref.item(n).text()) + if n != 0: + data['references'] = refs + return yaml.dump(data, default_flow_style=False) + + def export(self): + if QDir().mkpath(QDir().homePath() + "/mageia-advisories/advisories"): + if self.ui.bug_le.text() != "": + #TODO check that it exists + with open(f"{QDir().homePath()}/mageia-advisories/advisories/{self.ui.bug_le.text()}.adv", 'w') as f: + f.write(self.adv_text()) + + def cancel(self): + self.close() + + def preview(self): + dl = QDialog() + dl.setWindowTitle("Advisory preview") + te = QTextEdit() + te.setPlainText(self.adv_text()) + te.setReadOnly(True) + te.setMinimumSize(600, 0) + ok_bt = QPushButton("OK") + layout = QVBoxLayout() + layout.addWidget(te) + layout.addWidget(ok_bt) + dl.setLayout(layout) + ok_bt.clicked.connect(dl.close) + dl.exec() + + def sanitize_line(self, line): + if len(line) != 0: + return line.splitlines()[0].strip() + else: + return "" + + def valid_number(self): + self.ui.bug_le.setText(re.sub('\D', '', self.ui.bug_le.text())) + +if __name__ == "__main__": + app = QApplication(sys.argv) + widget = Widget() + widget.show() + sys.exit(app.exec()) |