التقاء مضمنة إحصاءات التعليقات

كيفية جمع إحصاءات تعليق الصفحة في التقاء؟

نعم ، ولماذا قد تكون هناك حاجة لهذا؟



لماذا ولماذا


في المشروع الذي صادفت فيه العمل ، ولدت العملية التالية لإعداد المتطلبات والموافقة عليها:

  • تم استخدام التقاء للتوثيق.
  • أعد فريق المورد وصفًا لعمليات الأعمال وخطواتها في شكل صفحات منفصلة وفقًا للقالب.
  • مرة واحدة في الأسبوع ، تم تسليم مجموعة من الأوصاف المعدة للعميل لتصحيحها.
  • ترك فريق العملاء جميع الأسئلة والإضافات على الصفحة المقابلة في شكل تعليقات مدمجة.
  • واستكمل فريق المورد المحتوى ، ورد على التعليقات والأسئلة الثابتة لمزيد من الدراسة.
  • إذا تمت الإجابة عن السؤال وتم تحديث المحتوى أو تم إصلاح مهمة الدراسة ، فيجب على فريق العميل إغلاق التعليق.
  • يجب إغلاق الأسئلة المتعلقة بدفعة من المستندات من الأسبوع الحالي بحلول وقت نقل الدفعة التالية الأسبوع المقبل.

كل أسبوع ، على مديري المشاريع مهمة لفهم مقدار عمل مجموعة المستندات التي تم تسليمها وما الذي يمكن اعتباره جاهزًا بشكل مشروط منه. ويحتاج المشاركون في فريق المورد بشكل دوري إلى التحقق من حالة التعليقات على مستنداتهم والعمل بشكل هادف مع البقية. ولكن كيف يمكن العثور عليها؟ يمكنك فتح كل صفحة ، والبحث عن أول تعليق عليها بعينيك (أو بمساعدة خدعة صغيرة ) ، ثم النقر فوق كل التعليقات ، لا يتعجل فريق العميل إغلاقها والتفكير في كل منها والتحقق من الإجابة.

تحتوي الدُفعة الأسبوعية على 50-100 صفحة منفصلة ، وللقيام بذلك بيديك ، هناك قدر كبير من العمل. وإذا كنت لا تزال تحاول جمع الحجج لإقناع الجانب الآخر ، فستصبح حزينة للغاية. وهناك أيضًا تعليقات متدلية تنتج عن التحرير غير الدقيق للصفحة عندما يتم حذف النص المصدر بطريق الخطأ. يكون هذا التعليق مرئيًا في التعليقات التي تم حلها ، لكن لا يمكن إعادة فتحها (يمكنك ، إذا قمت بإعادة إنشاء علامة غير مرئية في نص الصفحة).

البحث عن الأدوات لم ينجح. بالإضافة إلى ذلك ، يتم نشر التقاء على جانب العميل ، لا يمكنك تثبيت المكونات الإضافية ، ناهيك عن شراء. لا خبرة في تطوير الاقتصاد الكلي.

في مرحلة ما ، تذكرت API Confluence REST والخبرة السابقة في استخدام واجهة برمجة تطبيقات Jira المشابهة. أظهر البحث والتجارب مع وظائف الاتصال من المستعرض أنه يمكنك الوصول إلى التعليقات وخصائصها. بعد ذلك ، كان عليك اختيار أداة للتشغيل الآلي ، ويمكنك البدء في حلها. لدي بعض الخبرة في إنشاء برامج نصية على أدوات أقرب إلى المسؤولين مثل Bash و Perl و JScript. لست مطورًا ، ولم يكن لدي أي أدوات مألوفة أو مألوفة. أردت أن أجرب شيئًا أكثر شيوعًا أو مناسبًا. ثم اكتشفت غلافاً لبيثون API وقررت تجربته.

المبدأ العام


تم صياغة المشكلة على النحو التالي. تحتاج إلى العثور على جميع الصفحات المتعلقة بتسليم أسبوعي محدد. اجمع التعليقات عليها في قائمة: صفحة ، رابط للتعليق ، مؤلف وتاريخ التعليق ، نص مصدر في الصفحة ، تعليق وإجابات ، مؤلف وتاريخ آخر رد ، حالة تعليق. بالإضافة إلى ذلك ، جمع إحصائيات لكل صفحة ، وعدد التعليقات في المجموع ، وعدد المخاطر ، وعدد الصفحات المفتوحة. احفظ كل شيء على صفحة إحصائيات خاصة.

أضع بيثون ، انظر إلى أساسيات العمل معها ، ودعنا نذهب. أولاً ، قم بإنشاء اتصال:

from atlassian import Confluence UserLogin = 'xxxxxx' # input("Login: ") UserPwd = 'xxxxxx' # input("Password: ") confluenceURL = 'http://wiki.xxxxxx' confluence = Confluence( url=confluenceURL, username=UserLogin, password=UserPwd) 

للبحث عن صفحات من مجموعة أسبوعية ، قررت استخدام العلامات. كيفية إيصالها بشكل جماعي هي مهمة منفصلة.

 page_label = 'week123' cql = 'space.key={} and label = "{}" and type = page ' 'ORDER BY title '.format('YYY', page_label) pages = confluence.cql(cql, expand=None, start=0, limit=200) 

لذلك لدينا قائمة الصفحات للتحقق. بعد ذلك ، نبدأ في معالجة كل صفحة على حدة. نحن نجمع من بياناتها على التعليقات مع المعلمات الخاصة بهم. بناءً على هذه البيانات ، نقوم ببناء إحصائيات حول عدد التعليقات الموجودة على الصفحة وفي أي ظروف. بعد ذلك ، نطرق النتيجة لجميع الصفحات ونبدأ في تنسيق النتيجة. نقوم بإنشاء نص الصفحة والنتيجة في شكل جدول إحصائيات وقائمة مفصلة بالتعليقات المفتوحة.

معالجة قائمة الصفحات
 statistics = [] open_comments = [] #  - ? if pages is not None: #    ? if pages['size'] > 0: for page in pages['results']: print(page['title']) #       , #  page_comments = page_comments_data(page['content']['id']) #     statistics.append(page_statistics(page_comments)) #        #    . for comment in page_comments: if comment['Result'] not in ['resolved', 'nocomment']: if not (comment['Result'] == 'dangling' and comment['Author'] in excludeNames): open_comments.append(comment) #       . statistics.append(total_statistics(statistics)) #     page_id = confluence.get_page_id(space='YYY', title=page_title) #     ,    . page_body = ('<p><ac:structured-macro ac:name="toc" ac:schema-version="1"' '/></p>' '<h1>Comments Statistics</h1>{}' '<h1>Open Comments List</h1>{}' ).format(create_table(statistics), create_table(open_comments)) #  if page_id is not None: status = confluence.update_page( page_id=page_id, title=page_title, body=page_body, representation='storage' ) 

ميزات API


الآن دعونا نتعرف على كيفية معالجة الصفحة. بشكل افتراضي ، تقوم واجهة برمجة التطبيقات بإرجاع المعلومات الأساسية فقط ، مثل المعرف أو اسم الصفحة. يجب تحديد جميع الخصائص الإضافية بشكل صريح. يمكن رؤيتها من خلال تحليل نتيجة المكالمة. يمكن العثور على بيانات إضافية في أقسام أو أقسام فرعية من _expandable. نضيف العنصر المطلوب للتوسع وننظر إلى أبعد من ذلك حتى نعثر على البيانات اللازمة.

مثال المشكلة
 http://wiki.xxxxxx/rest/api/content/101743895?expand=body,children.comment { "id": "97517865", "type": "page", "status": "current", "title": "w2019-47 comments status", "children": { "comment": { "results": [], "start": 0, "limit": 25, "size": 25, "_links": {} }, "_links": {}, "_expandable": { "attachment": "/rest/api/content/97517865/child/attachment", "page": "/rest/api/content/97517865/child/page" } }, "body": { "_expandable": { "editor": "", "view": "", "export_view": "", "styled_view": "", "storage": "", "anonymous_export_view": "" } }, "extensions": { "position": "none" }, "_links": {}, "_expandable": { "metadata": "", "operations": "", "restrictions": "/rest/api/content/97517865/restriction/byOperation", "history": "/rest/api/content/97517865/history", "ancestors": "", "version": "", "descendants": "/rest/api/content/97517865/descendant", } } 

وهناك أيضا قيود على عدد النتائج الصادرة ، ترقيم الصفحات. تم تكوينه على جانب الخادم (API؟) وفي حالتنا هو 25. بالنسبة لبعض الطلبات ، يمكن تغييره عن طريق تحديد صراحة ، لكنه لن يعمل إلا للمستوى العلوي. وكشف التعليقات على الصفحة ، نحصل على نفس الشيء فقط 25 ، بينما الحجم مزيف أيضًا. في المثال كان هناك 29 في الواقع. تمكنا من التحايل على ترقيم الصفحات من التعليقات باستخدام وظيفة منفصلة في وحدة التقاء - get_page_comments مع القدرة على تحديد حجم الصفحة.

 #    import re #      XML def replace_chars2(in_text): text = re.sub(r'&', '&', in_text) text = re.sub(r'\'', ''', text) text = re.sub(r'<', '<', text) text = re.sub(r'>', '>', text) text = re.sub(r'"', '"', text) return text 

وكان المأزق التالي ينتظر في ميزات الحفاظ على إصدار أحرف خاصة وإصدارها. يمكن الحصول على نص الصفحة أو التعليق في عدة طرق عرض: XML داخلي - تخزين ، HTML وسيط بدون إخراج الماكرو - عرض و HTML مع إخراج الماكرو - export_view. لكن عنوان عنوان الصفحة ونص التعليق الأصلي الأصلي حدد دائمًا في شكل مناسب للقراءة. لأن في المستقبل ، تقع هذه البيانات في صلب الصفحة مع الإحصاءات ، ثم أدت بعض الأحرف إلى حدوث أخطاء في التحويل. كان علي أن أكتب إجراء استبدال أعلاه.

تعليقات الصفحة


الآن لتحليل الصفحة. هذا أحد الإجراءات التي تقوم بتحميل الصفحة ، وجمع بياناتها ، ثم تسحب قائمة بالتعليقات مع الإجابات وتجميعها في المراسلات. والنتيجة هي قائمة من القواميس ، حيث يتوافق كل عنصر من عناصر القائمة مع تعليق واحد مع الإجابات. وجميع سمات هذا التعليق تكمن في الحقول المقابلة من القاموس.

معالجة صفحة واحدة
 def page_comments_data(page_identifier): #,      ,  , #   , #  ,    ,    #   (). expand_text = ('body.storage,extensions.inlineProperties' ',extensions.resolution,version,children.comment' ',children.comment.version,children.comment.body.storage' ) #    .     . conf_page = confluence.get_page_by_id(page_identifier, expand='body.storage') page_title = replace_chars2(conf_page['title']) #   . link_base = conf_page['_links']['base'] page_link = link_base + conf_page['_links']['webui'] page_code = '<a href="{}">{}</a>'.format(page_link, page_title) #   page_comments = confluence.get_page_comments(content_id=page_identifier, start=0, limit=1000, comments = [] #    for comment in page_comments['results']: #      - . if comment['extensions']['location'] == 'footer': continue #  comment_text = comment['body']['storage']['value'] comment_result = comment['extensions']['resolution']['status'] comment_link = '<a href="{}">{}</a>'\ .format(link_base + comment['_links']['webui'], 'link') #  comment_link = re.sub(r'&focusedCommentId=', '&focusedCommentId=', comment_link) #  created_when = re.sub(r'\.000\+', ' GMT+', re.sub(r'T', ' ', comment['version']['when'])) created_by = comment['version']['by']['displayName'] orig_text = replace_chars2(comment['extensions'] ['inlineProperties']['originalSelection']) #    /. thread = '<b>To text: </b>{}<br/><b>At: </b>{}<br/><b>By: ' '</b>{}<br/>{}'.format(orig_text, created_when, created_by, comment_text) last_by = '' last_when = '' #  answers = comment['children']['comment']['size'] if answers > 0: for message in comment['children']['comment']['results']: #  last_when = re.sub(r'\.000\+', ' GMT+', re.sub(r'T', ' ', message['version']['when'])) last_by = message['version']['by']['displayName'] #  thread += ('<br/>===next===<br/><b>At: </b>{}<br/><b>By: ' '</b>{}<br/>{}'.format(last_when, last_by, message['body']['storage']['value']) ) #  . row_comm = {"Page": page_code, "Comment": comment_link, "Thread": thread, "Result": comment_result, "Answers count": answers, "Creation Date": created_when, "Author": created_by, "Last Date": last_when, "Last Author": last_by} comments.append(row_comm) #   ,   , #     . if len(comments) == 0: row_comm = {"Page": page_code, "Comment": 'nolink', "Thread": 'nocomment', "Result": 'nocomment', "Answers count": 0, "Creation Date": 'never', "Author": 'nobody', "Last Date": 'never', "Last Author": 'nobody'} comments.append(row_comm) return comments 

الإحصاءات والجداول


من أجل وضوح عرض البيانات ، نجمع إحصاءات عنها ونرتبها في شكل جداول.

نعالج الإحصاءات
 def page_statistics(comments_data): open_count = 0 dang_count = 0 comment_count = len(comments_data) if comment_count > 0: for comment in comments_data: #     if comment['Result'] not in ['resolved', 'nocomment']: if comment['Result'] in ['open', 'reopened']: open_count += 1 if comment['Result'] == 'dangling' and comment['Author'] not in excludeNames: dang_count += 1 res_dict = {'Page': comments_data[0]['Page'], 'Total': comment_count, 'Resolved': comment_count - open_count - dang_count, 'Dangling': dang_count, 'Open': open_count} return res_dict #   def total_statistics(stat_data): total_comment = 0 total_resolved = 0 total_open = 0 total_dangling = 0 for statRow in stat_data: total_comment += statRow['Total'] total_resolved += statRow['Resolved'] total_open += statRow['Open'] total_dangling += statRow['Dangling'] res_dict = {'Page': 'All Pages Total', 'Type': '', 'Jira': '', 'Status': '', 'Total': total_comment, 'Resolved': total_resolved, 'Dangling': total_dangling, 'Open': total_open} return res_dict 

لجعل البيانات في شكل جداول ، سنفعل إجراء آخر. إنها تشكل كود HTML للجدول من قائمة القواميس ، حيث تضيف العناوين سطرًا من أسماء مفاتيح القاموس وتضيف عمودًا يحتوي على أرقام الأسطر.

 def create_table(tab_data): tab_start = '<table style="width: 100.00%;"><colgroup><col />' '<col /></colgroup><tbody>' tab_end = '</tbody></table>' tab_code = tab_start + '<tr>' row_num = 1 if len(tab_data) > 0: tab_code += '<th>Num</th>' for key in tab_data[0].keys(): tab_code += '<th>{}</th>'.format(key) tab_code += '</tr>' for row in tab_data: tab_code += '<tr><td>{}</td>'.format(row_num) row_num += 1 for field in row.values(): tab_code += '<td>{}</td>'.format(field) tab_code += '</tr>' tab_code += tab_end + '\n' return tab_code 

الآن كل شيء جاهز. بعد تصنيف البرنامج النصي وتشغيله ، نحصل على صفحة تبدو كما يلي:



PS

بالطبع ، هذا ليس كل ما ظهر في النهاية. كان هناك تحليل للصفحات والبحث عن ماكرو مع رقم المهمة في جيرا. كان هناك تصنيف تلقائي بواسطة أرقام المهام في جيرا وروابط منها إلى التقاء. كان هناك مقارنة والتحقق من قوائم التسليم الأسبوعية. كان هناك حفظ للتعليقات في Excel وجمع البيانات الشائعة من عدة ملفات Excel أسبوعية. ومؤخرًا تحليل التعليقات من Word تمت إضافته.

Source: https://habr.com/ru/post/ar485652/


All Articles