Exporting case details from FogBugz

核能气质少年 提交于 2020-01-04 02:36:08

问题


We are seeking to create a snapshot of all our FogBugz data however the GUI only seems to allow to export the top level list of cases, not their detail/attachments. Searching around the only solutions I can find relate to apps that are now out of date.


回答1:


I found this very hard to find any help on but eventually I figured out how to write a script to do this and wanted to share it. Please note I'm not a Python programmer nor a HTML/CSS guy so no flaming please!

It started as a sample script from their help site and I adapted it to include attachments and to be stand alone.

First download and install Python3. Then pip install fogbugz and jinja2. Place these two files in your python directory, fillin the variables (including the token half way down the script) and then run backit.

1- backit.py

from fogbugz import FogBugz
import sys
from jinja2 import Template
import os
import urllib

def main():

  S_FOGBUGZ_URL   = 'https://whatever.fogbugz.com/'
  S_EMAIL         = 'email'
  S_PASSWORD      = 'pass'
  MAX_BUGS        = 9999

  TEMPLATE_FILE = 'C:\\Users\\zzz\\AppData\\Local\\Programs\\Python\\Python36\\fbBackupTemplate.html'

  fb = FogBugz(S_FOGBUGZ_URL)
  fb.logon(S_EMAIL, S_PASSWORD)

  resp = fb.search(q='type:"Cases"',
                   cols='ixBug',
                   max=MAX_BUGS)

  tmpl = Template(open(TEMPLATE_FILE,'r').read())

  for case in resp.cases.findAll('case'):
      ixBug = int(case['ixBug'])
      print(ixBug)



      respBug = fb.search(q='%s' % ixBug,cols ='sTitle,sPersonAssignedTo,sProject,sArea,sCategory,sPriority,events')
      xmlBug = respBug.cases.findAll('case')[0]



      bug = {}
      bug['ixBug'] = int(xmlBug['ixBug'])
      bug['sTitle'] = xmlBug.sTitle.string if xmlBug.sTitle.string else ''
      bug['sPersonAssignedTo'] = xmlBug.sPersonAssignedTo.string if xmlBug.sPersonAssignedTo.string else ''
      bug['sProject'] = xmlBug.sProject.string if xmlBug.sProject.string else ''
      bug['sArea'] = xmlBug.sArea.string if xmlBug.sArea.string else ''
      bug['sCategory'] = xmlBug.sCategory.string if xmlBug.sCategory.string else ''
      bug['sPriority'] = xmlBug.sPriority.string if xmlBug.sPriority.string else ''
      bug['events'] = []

      BACKUP_DIR = 'C:\\Temp\\FBBack'
      BACKUP_DIR += '\\' + xmlBug.sProject.string if xmlBug.sProject.string else ''

      if not os.path.exists(BACKUP_DIR):
        os.makedirs(BACKUP_DIR)

      BACKUP_DIR += '\\' + str(xmlBug['ixBug'])

      if not os.path.exists(BACKUP_DIR):
        os.makedirs(BACKUP_DIR)

      for event in xmlBug.events.findAll('event'):
        bugEvent = {}
        bugEvent['ixBugEvent'] = int(event['ixBugEvent'])
        bugEvent['sVerb'] = event.sVerb.string if event.sVerb.string else ''
        bugEvent['dt'] = event.dt.string if event.dt.string else ''
        bugEvent['s'] = event.s.string if event.s.string else ''
        bugEvent['sChanges'] = event.sChanges.string if event.sChanges.string else ''
        bugEvent['evtDescription'] = event.evtDescription.string if event.evtDescription.string else ''
        bugEvent['sPerson'] = event.sPerson.string if event.sPerson.string else ''    
        bugEvent['s'] = event.s.string.encode('ascii', 'ignore').decode('utf-8') if event.s.string else ''
        theAttachments = ''
        for att in event.rgAttachments:
          theAttachments += 'Attachment: ' +att.sFileName.string + '\n'

          print('Downloading attachment: ' + att.sFileName.string)
          str1 = att.sURL.string
          str2 = 'ixAttachment='
          loc1 = str1.find(str2) + len(str2)
          loc2 = str1.find('&sFileName')

          str3 = ';sFileName='
          loc3 = str1.find(str3) + len(str3)
          loc4 = str1.find('&sTicket')

          theURL = S_FOGBUGZ_URL #+ att.sURL.string
          theURL += 'default.asp?'
          theURL += 'ixAttachment=' + str1[loc1:loc2]
          theURL += '&pg=pgDownload&pgType=pgFile&sFilename=' + str1[loc3:loc4]
          theURL += '&token=123456sometoken'

          #fix the replace
          newFileName = att.sFileName.string.replace('\\','')
          newFileName = newFileName.replace(':','')
          newFileName = BACKUP_DIR+'\\'+newFileName
          #print(newFileName)
          urllib.request.urlretrieve(theURL, newFileName)
        bugEvent['attachment'] = theAttachments
        bug['events'].append(bugEvent)




      f = open('%s\\%s.html' % (BACKUP_DIR,bug['ixBug']),'w')
      f.write(tmpl.render(bug=bug))
      f.close()
      fb.view(ixBug=ixBug)


main()

2- fbBackupTemplate.html

<!DOCTYPE html>
<html lang="en">
<head>
  <title>{{bug.ixBug|e}} | {{bug.sTitle|e}}</title>
  <style type="text/css">
    .bugHeader {
      outline-width: 2px;
      outline-style: solid;
      width: 90%;
      padding: 5px;
      background: #B8DDFF;
      font: 24px "Trebuchet MS", Arial, Helvetica, sans-serif;
    }
    .bugEvent {
      outline-width: 2px;
      outline-style: solid;
      outline-color: blue;
      width: 90%;
      padding: 5px;
      background: #D2E9FF;
      font: 12px Arial, Helvetica, sans-serif;
    }

    pre.s {
      white-space: pre-wrap;
    }
  </style>    
</head>
<body>
  <div class="bugHeader">
    <span class="ixBug">Bug ID: {{bug.ixBug|e}}</span><br>
    <span class="sTitle">Title: {{bug.sTitle|e}}</span><br>
    <span class="sPersonAssignedTo">Assigned To: {{bug.sPersonAssignedTo|e}}</span><br>
    <span class="sProject">Project: {{bug.sProject|e}}</span><br>
    <span class="sArea">Area: {{bug.sArea|e}}</span><br>
    <span class="sCategory">Category: {{bug.sCategory|e}}</span><br>
    <span class="sPriority">Title: {{bug.sPriority|e}}</span><br>
  </div>
  <div class="bugEvents">
    {% for event in bug.events %}
      <div class="bugEvent">
        <span class="ixBugEvent">BugEvent ID: {{event.ixBugEvent|e}}</span><br>
        <span class="dt">Date/Time: {{event.dt|e}}</span><br>
        <span class="sVerb">Verb: {{event.sVerb|e}}</span><br>
        <span class="evtDescription">Event Description: {{event.evtDescription|e}}</span><br>
        <span class="sChanges">Changes: {{event.sChanges|e}}</span><br>
        <span class="sPerson">Person: {{event.sPerson|e}}</span><br>
        <span class="Text">Text: </span><br>
        <pre class="s">{{event.s|e}}</pre><br>
        <pre class="s">{{event.attachment|e}}</pre><br>
      </div>
    {% endfor %}
  </div>
</body>
</html>

Original URL for the backup script: https://developers.fogbugz.com/?W211

Get a token for the API call: https://support.fogbugz.com/hc/en-us/articles/360011255754-Generating-a-FogBugz-XML-API-Token



来源:https://stackoverflow.com/questions/46521253/exporting-case-details-from-fogbugz

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!