Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
title: "Передать\nзадание"
tooltip: "Создать и передать задание между разделами"
author: CPSK
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
"""Открывает мастер передачи задания между разделами."""

__title__ = "Передать\nзадание"
__author__ = "CPSK"

import os
import sys


SCRIPT_DIR = os.path.dirname(__file__)
EXTENSION_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))))
LIB_DIR = os.path.join(EXTENSION_DIR, "lib")
if LIB_DIR not in sys.path:
sys.path.insert(0, LIB_DIR)

from gip_tasks import commands


commands.run_create_task(__revit__.ActiveUIDocument)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
title: "Журнал\nзаданий"
tooltip: "Открыть журнал заданий между разделами"
author: CPSK
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
"""Открывает журнал заданий между разделами."""

__title__ = "Журнал\nзаданий"
__author__ = "CPSK"

import os
import sys


SCRIPT_DIR = os.path.dirname(__file__)
EXTENSION_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))))
LIB_DIR = os.path.join(EXTENSION_DIR, "lib")
if LIB_DIR not in sys.path:
sys.path.insert(0, LIB_DIR)

from gip_tasks import commands


commands.run_journal(__revit__.ActiveUIDocument)
5 changes: 5 additions & 0 deletions pyrevit.extension/lib/gip_tasks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
"""GIP Tasks MVP package for pyRevit."""

APP_NAME = "GIP Tasks"

97 changes: 97 additions & 0 deletions pyrevit.extension/lib/gip_tasks/api_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
import json
import sys
try:
import urllib2
from urllib import urlencode
except ImportError:
import urllib.request as urllib2
from urllib.parse import urlencode

from . import config


DEFAULT_TIMEOUT_SECONDS = 3


class ApiError(Exception):
pass


class ApiClient(object):
def __init__(self, settings=None):
self.settings = settings or config.load()
self.base_url = (self.settings.get("API_BASE_URL") or "").rstrip("/")
self.token = self.settings.get("AUTH_TOKEN") or ""
self.timeout = self._timeout()

def _timeout(self):
try:
return max(1, int(self.settings.get("API_TIMEOUT_SECONDS") or DEFAULT_TIMEOUT_SECONDS))
except Exception:
return DEFAULT_TIMEOUT_SECONDS

def request(self, method, path, payload=None, query=None):
if not self.base_url:
raise ApiError("API_BASE_URL is empty")
url = self.base_url + path
if query:
clean = {}
for key, value in query.items():
if value is not None and value != "":
clean[key] = value
if clean:
url += "?" + urlencode(clean)
body = None
headers = {"Accept": "application/json", "Content-Type": "application/json"}
if self.token:
headers["Authorization"] = "Bearer " + self.token
if payload is not None:
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
req = urllib2.Request(url, data=body, headers=headers)
req.get_method = lambda: method
try:
res = urllib2.urlopen(req, timeout=self.timeout)
raw = res.read()
if not raw:
return {}
if sys.version_info[0] < 3:
raw = raw.decode("utf-8")
return json.loads(raw)
except Exception as exc:
raise ApiError(str(exc))

def get_projects(self):
return self.request("GET", "/projects")

def create_project(self, payload):
return self.request("POST", "/projects", payload)

def list_tasks(self, project_id, filters=None):
if not project_id:
raise ApiError(u"Сначала выберите проект")
query = {"project_id": project_id}
query.update(filters or {})
return self.request("GET", "/tasks", query=query)

def create_task(self, payload):
if not payload.get("project_id"):
raise ApiError(u"Сначала выберите проект")
return self.request("POST", "/tasks", payload)

def patch_task(self, task_id, project_id, payload):
if not project_id:
raise ApiError(u"Сначала выберите проект")
payload = payload or {}
payload["project_id"] = project_id
return self.request("PATCH", "/tasks/%s" % task_id, payload)

def add_comment(self, task_id, project_id, comment):
if not project_id:
raise ApiError(u"Сначала выберите проект")
return self.request("POST", "/tasks/%s/comments" % task_id, {"project_id": project_id, "comment": comment})

def task_changes(self, project_id, since=None):
if not project_id:
raise ApiError(u"Сначала выберите проект")
return self.request("GET", "/tasks/changes", query={"project_id": project_id, "since": since})
52 changes: 52 additions & 0 deletions pyrevit.extension/lib/gip_tasks/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
from pyrevit import forms


def show_short_error(message):
forms.alert(message, title="GIP Tasks")


def log_exception(message):
try:
from . import logger
logger.exception(message)
except Exception:
pass


def run_create_task(uidoc):
try:
from . import config, revit_context, task_models, task_service
from . import marker_service
from .ui.create_task_window import CreateTaskWindow

doc = uidoc.Document
settings = config.load()
ctx = revit_context.collect(uidoc)
win = CreateTaskWindow(settings, ctx, uidoc)
if not win.show_dialog():
return None
marker = win.selected_marker
if not marker:
show_short_error(u"Сначала выберите маркер задания семейства CPSK_Маркер задания на активном виде.")
return None
payload = task_models.new_task_payload(config.load(), win.result, win.revit_context)
payload, status = task_service.create_task(payload)
marker_service.write_task_to_marker(doc, marker, payload)
forms.alert(status, title="GIP Tasks", warn_icon=False)
return payload
except Exception:
log_exception("Create task command failed")
show_short_error(u"Не удалось передать задание. Подробности записаны в лог.")
return None


def run_journal(uidoc):
try:
from .ui.task_journal_window import TaskJournalWindow

win = TaskJournalWindow(uidoc)
win.show_dialog()
except Exception:
log_exception("Journal command failed")
show_short_error(u"Не удалось открыть журнал. Подробности записаны в лог.")
96 changes: 96 additions & 0 deletions pyrevit.extension/lib/gip_tasks/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
import json
import os


DEFAULTS = {
"API_BASE_URL": "",
"AUTH_TOKEN": "",
"COMPANY_ID": "demo-company",
"CURRENT_PROJECT_ID": "",
"CURRENT_PROJECT_NAME": "",
"CURRENT_PROJECT_CODE": "",
"CURRENT_DISCIPLINE": "КЖ",
"CURRENT_USER": "",
"CURRENT_USER_ROLE": "project_coordinator",
"LOCAL_MODE": True,
"LOCAL_CACHE_PATH": "",
"API_TIMEOUT_SECONDS": 3,
"POLLING_INTERVAL_SECONDS": 30,
"MARKER_FAMILY_NAME": "CPSK_Маркер задания",
"MARKER_FAMILY_TYPE": "Новое",
"MARKER_FAMILY_PATH": r"C:\Users\saukouma\Documents\BIM библиотека\2-Семейства\Задания\CPSK_Маркер задания.rfa",
}


def _ensure_dir(path):
if path and not os.path.isdir(path):
os.makedirs(path)
return path


def appdata_dir():
base = os.environ.get("APPDATA") or os.path.expanduser("~")
return _ensure_dir(os.path.join(base, "GIPTasks"))


def extension_root():
return os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))


def config_path():
return os.path.join(appdata_dir(), "config.json")


def _normalize(data):
data["MARKER_FAMILY_NAME"] = DEFAULTS["MARKER_FAMILY_NAME"]
data["MARKER_FAMILY_TYPE"] = DEFAULTS["MARKER_FAMILY_TYPE"]
if not data.get("CURRENT_DISCIPLINE"):
data["CURRENT_DISCIPLINE"] = DEFAULTS["CURRENT_DISCIPLINE"]
if not data.get("LOCAL_CACHE_PATH"):
data["LOCAL_CACHE_PATH"] = os.path.join(appdata_dir(), "gip_tasks_cache.sqlite")
data["LOCAL_MODE"] = not bool((data.get("API_BASE_URL") or "").strip())
return data


def load():
data = DEFAULTS.copy()
path = config_path()
if os.path.exists(path):
try:
with open(path, "rb") as fp:
data.update(json.loads(fp.read().decode("utf-8")))
except Exception:
pass
return _normalize(data)


def save(values):
data = DEFAULTS.copy()
data.update(values or {})
data = _normalize(data)
_ensure_dir(os.path.dirname(config_path()))
raw = json.dumps(data, indent=2, ensure_ascii=False, sort_keys=True)
with open(config_path(), "wb") as fp:
fp.write(raw.encode("utf-8"))
return data


def set_current_project(project):
data = load()
data["CURRENT_PROJECT_ID"] = project.get("id") or project.get("project_id") or ""
data["CURRENT_PROJECT_NAME"] = project.get("name") or project.get("project_name") or ""
data["CURRENT_PROJECT_CODE"] = project.get("code") or project.get("project_code") or ""
if project.get("user_role"):
data["CURRENT_USER_ROLE"] = project.get("user_role")
return save(data)


def can_create_project(settings=None):
role = (settings or load()).get("CURRENT_USER_ROLE") or ""
return role in ("admin", "project_coordinator", "lead_specialist")


def is_local_mode(settings=None):
settings = settings or load()
return bool(settings.get("LOCAL_MODE")) or not bool((settings.get("API_BASE_URL") or "").strip())
Loading