mirror of
https://github.com/moparisthebest/SickRage
synced 2024-10-31 15:35:01 -04:00
Fix for duplicate tickets being submitted via app, title variable was being appended to.
Added in code to send the last 50 lines of app's logs to pastebin then give back a url.
This commit is contained in:
parent
b2d5ef531b
commit
f40d5e1310
@ -589,6 +589,16 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="field-pair">
|
||||
<label for="git_autoissues">
|
||||
<span class="component-title">Git auto-issues submit</span>
|
||||
<span class="component-desc">
|
||||
<input type="checkbox" name="git_autoissues" id="git_autoissues" #if True == $sickbeard.GIT_AUTOISSUES then 'checked="checked"' else ''#/>
|
||||
<p>automatically submit bug/issue reports to our issue tracker when errors are logged</p>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<input type="submit" class="btn config_submitter" value="Save Changes" />
|
||||
</fieldset>
|
||||
|
||||
|
710
lib/pastebin.py
Normal file
710
lib/pastebin.py
Normal file
@ -0,0 +1,710 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# Pastebin.py - Python 3.2 Pastebin API.
|
||||
# Copyright (C) 2012 Ian Havelock
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
# This software is a derivative work of:
|
||||
# http://winappdbg.sourceforge.net/blog/pastebin.py
|
||||
|
||||
#############################################################################
|
||||
|
||||
|
||||
__all__ = ['delete_paste', 'user_details', 'trending', 'pastes_by_user',
|
||||
'generate_user_key', 'paste', 'PastebinAPI', 'PastebinError']
|
||||
|
||||
import sys
|
||||
import urllib
|
||||
|
||||
class PastebinError(RuntimeError):
|
||||
"""Pastebin API error.
|
||||
|
||||
The error message returned by the web application is stored as the Python
|
||||
exception message."""
|
||||
|
||||
class PastebinAPI(object):
|
||||
"""Pastebin API interaction object.
|
||||
|
||||
Public functions:
|
||||
|
||||
paste -- Pastes a user-specified file or string using the new API-key POST
|
||||
method.
|
||||
|
||||
generate_user_key -- Generates a session-key that is required for other
|
||||
functions.
|
||||
|
||||
pastes_by_user -- Returns all public pastes submitted by the specified login
|
||||
credentials.
|
||||
|
||||
trending -- Returns the top trending paste.
|
||||
|
||||
user_details -- Returns details about the user for the specified API user
|
||||
key.
|
||||
|
||||
delete_paste -- Adds two numbers together and returns the result."""
|
||||
|
||||
# String to determine bad API requests
|
||||
_bad_request = 'Bad API request'
|
||||
|
||||
# Base domain name
|
||||
_base_domain = 'pastebin.com'
|
||||
|
||||
# Valid Pastebin URLs begin with this string (kinda bvious)
|
||||
_prefix_url = 'http://%s/' % _base_domain
|
||||
|
||||
# Valid Pastebin URLs with a custom subdomain begin with this string
|
||||
_subdomain_url = 'http://%%s.%s/' % _base_domain
|
||||
|
||||
# DEPRECATED
|
||||
# URL to the LEGACY POST API
|
||||
#_legacy_api_url = 'http://%s/api_public.php' % _base_domain
|
||||
|
||||
# URL to the POST API
|
||||
_api_url = 'http://%s/api/api_post.php' % _base_domain
|
||||
|
||||
# URL to the Login API
|
||||
_api_login_url = 'http://%s/api/api_login.php' % _base_domain
|
||||
|
||||
# Valid paste_expire_date values (Never, 10 minutes, 1 Hour, 1 Day, 1 Month)
|
||||
paste_expire_date = ('N', '10M', '1H', '1D', '1M')
|
||||
|
||||
# Valid paste_expire_date values (0 = public, 1 = unlisted, 2 = private)
|
||||
paste_private = ('public', 'unlisted', 'private')
|
||||
|
||||
# Valid parse_format values
|
||||
paste_format = (
|
||||
'4cs', # 4CS
|
||||
'6502acme', # 6502 ACME Cross Assembler
|
||||
'6502kickass', # 6502 Kick Assembler
|
||||
'6502tasm', # 6502 TASM/64TASS
|
||||
'abap', # ABAP
|
||||
'actionscript', # ActionScript
|
||||
'actionscript3', # ActionScript 3
|
||||
'ada', # Ada
|
||||
'algol68', # ALGOL 68
|
||||
'apache', # Apache Log
|
||||
'applescript', # AppleScript
|
||||
'apt_sources', # APT Sources
|
||||
'asm', # ASM (NASM)
|
||||
'asp', # ASP
|
||||
'autoconf', # autoconf
|
||||
'autohotkey', # Autohotkey
|
||||
'autoit', # AutoIt
|
||||
'avisynth', # Avisynth
|
||||
'awk', # Awk
|
||||
'bascomavr', # BASCOM AVR
|
||||
'bash', # Bash
|
||||
'basic4gl', # Basic4GL
|
||||
'bibtex', # BibTeX
|
||||
'blitzbasic', # Blitz Basic
|
||||
'bnf', # BNF
|
||||
'boo', # BOO
|
||||
'bf', # BrainFuck
|
||||
'c', # C
|
||||
'c_mac', # C for Macs
|
||||
'cil', # C Intermediate Language
|
||||
'csharp', # C#
|
||||
'cpp', # C++
|
||||
'cpp-qt', # C++ (with QT extensions)
|
||||
'c_loadrunner', # C: Loadrunner
|
||||
'caddcl', # CAD DCL
|
||||
'cadlisp', # CAD Lisp
|
||||
'cfdg', # CFDG
|
||||
'chaiscript', # ChaiScript
|
||||
'clojure', # Clojure
|
||||
'klonec', # Clone C
|
||||
'klonecpp', # Clone C++
|
||||
'cmake', # CMake
|
||||
'cobol', # COBOL
|
||||
'coffeescript', # CoffeeScript
|
||||
'cfm', # ColdFusion
|
||||
'css', # CSS
|
||||
'cuesheet', # Cuesheet
|
||||
'd', # D
|
||||
'dcs', # DCS
|
||||
'delphi', # Delphi
|
||||
'oxygene', # Delphi Prism (Oxygene)
|
||||
'diff', # Diff
|
||||
'div', # DIV
|
||||
'dos', # DOS
|
||||
'dot', # DOT
|
||||
'e', # E
|
||||
'ecmascript', # ECMAScript
|
||||
'eiffel', # Eiffel
|
||||
'email', # Email
|
||||
'epc', # EPC
|
||||
'erlang', # Erlang
|
||||
'fsharp', # F#
|
||||
'falcon', # Falcon
|
||||
'fo', # FO Language
|
||||
'f1', # Formula One
|
||||
'fortran', # Fortran
|
||||
'freebasic', # FreeBasic
|
||||
'freeswitch', # FreeSWITCH
|
||||
'gambas', # GAMBAS
|
||||
'gml', # Game Maker
|
||||
'gdb', # GDB
|
||||
'genero', # Genero
|
||||
'genie', # Genie
|
||||
'gettext', # GetText
|
||||
'go', # Go
|
||||
'groovy', # Groovy
|
||||
'gwbasic', # GwBasic
|
||||
'haskell', # Haskell
|
||||
'hicest', # HicEst
|
||||
'hq9plus', # HQ9 Plus
|
||||
'html4strict', # HTML
|
||||
'html5', # HTML 5
|
||||
'icon', # Icon
|
||||
'idl', # IDL
|
||||
'ini', # INI file
|
||||
'inno', # Inno Script
|
||||
'intercal', # INTERCAL
|
||||
'io', # IO
|
||||
'j', # J
|
||||
'java', # Java
|
||||
'java5', # Java 5
|
||||
'javascript', # JavaScript
|
||||
'jquery', # jQuery
|
||||
'kixtart', # KiXtart
|
||||
'latex', # Latex
|
||||
'lb', # Liberty BASIC
|
||||
'lsl2', # Linden Scripting
|
||||
'lisp', # Lisp
|
||||
'llvm', # LLVM
|
||||
'locobasic', # Loco Basic
|
||||
'logtalk', # Logtalk
|
||||
'lolcode', # LOL Code
|
||||
'lotusformulas', # Lotus Formulas
|
||||
'lotusscript', # Lotus Script
|
||||
'lscript', # LScript
|
||||
'lua', # Lua
|
||||
'm68k', # M68000 Assembler
|
||||
'magiksf', # MagikSF
|
||||
'make', # Make
|
||||
'mapbasic', # MapBasic
|
||||
'matlab', # MatLab
|
||||
'mirc', # mIRC
|
||||
'mmix', # MIX Assembler
|
||||
'modula2', # Modula 2
|
||||
'modula3', # Modula 3
|
||||
'68000devpac', # Motorola 68000 HiSoft Dev
|
||||
'mpasm', # MPASM
|
||||
'mxml', # MXML
|
||||
'mysql', # MySQL
|
||||
'newlisp', # newLISP
|
||||
'text', # None
|
||||
'nsis', # NullSoft Installer
|
||||
'oberon2', # Oberon 2
|
||||
'objeck', # Objeck Programming Langua
|
||||
'objc', # Objective C
|
||||
'ocaml-brief', # OCalm Brief
|
||||
'ocaml', # OCaml
|
||||
'pf', # OpenBSD PACKET FILTER
|
||||
'glsl', # OpenGL Shading
|
||||
'oobas', # Openoffice BASIC
|
||||
'oracle11', # Oracle 11
|
||||
'oracle8', # Oracle 8
|
||||
'oz', # Oz
|
||||
'pascal', # Pascal
|
||||
'pawn', # PAWN
|
||||
'pcre', # PCRE
|
||||
'per', # Per
|
||||
'perl', # Perl
|
||||
'perl6', # Perl 6
|
||||
'php', # PHP
|
||||
'php-brief', # PHP Brief
|
||||
'pic16', # Pic 16
|
||||
'pike', # Pike
|
||||
'pixelbender', # Pixel Bender
|
||||
'plsql', # PL/SQL
|
||||
'postgresql', # PostgreSQL
|
||||
'povray', # POV-Ray
|
||||
'powershell', # Power Shell
|
||||
'powerbuilder', # PowerBuilder
|
||||
'proftpd', # ProFTPd
|
||||
'progress', # Progress
|
||||
'prolog', # Prolog
|
||||
'properties', # Properties
|
||||
'providex', # ProvideX
|
||||
'purebasic', # PureBasic
|
||||
'pycon', # PyCon
|
||||
'python', # Python
|
||||
'q', # q/kdb+
|
||||
'qbasic', # QBasic
|
||||
'rsplus', # R
|
||||
'rails', # Rails
|
||||
'rebol', # REBOL
|
||||
'reg', # REG
|
||||
'robots', # Robots
|
||||
'rpmspec', # RPM Spec
|
||||
'ruby', # Ruby
|
||||
'gnuplot', # Ruby Gnuplot
|
||||
'sas', # SAS
|
||||
'scala', # Scala
|
||||
'scheme', # Scheme
|
||||
'scilab', # Scilab
|
||||
'sdlbasic', # SdlBasic
|
||||
'smalltalk', # Smalltalk
|
||||
'smarty', # Smarty
|
||||
'sql', # SQL
|
||||
'systemverilog', # SystemVerilog
|
||||
'tsql', # T-SQL
|
||||
'tcl', # TCL
|
||||
'teraterm', # Tera Term
|
||||
'thinbasic', # thinBasic
|
||||
'typoscript', # TypoScript
|
||||
'unicon', # Unicon
|
||||
'uscript', # UnrealScript
|
||||
'vala', # Vala
|
||||
'vbnet', # VB.NET
|
||||
'verilog', # VeriLog
|
||||
'vhdl', # VHDL
|
||||
'vim', # VIM
|
||||
'visualprolog', # Visual Pro Log
|
||||
'vb', # VisualBasic
|
||||
'visualfoxpro', # VisualFoxPro
|
||||
'whitespace', # WhiteSpace
|
||||
'whois', # WHOIS
|
||||
'winbatch', # Winbatch
|
||||
'xbasic', # XBasic
|
||||
'xml', # XML
|
||||
'xorg_conf', # Xorg Config
|
||||
'xpp', # XPP
|
||||
'yaml', # YAML
|
||||
'z80', # Z80 Assembler
|
||||
'zxbasic', # ZXBasic
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def delete_paste(self, api_dev_key, api_user_key, api_paste_key):
|
||||
"""Delete the paste specified by the api_paste_key.
|
||||
|
||||
|
||||
Usage Example::
|
||||
>>> from pastebin import PastebinAPI
|
||||
>>> x = PastebinAPI()
|
||||
>>> paste_to_delete = x.delete_paste('453a994e0e2f1efae07f8759e59e075b',
|
||||
... 'c57a18e6c0ae228cd4bd16fe36da381a',
|
||||
... 'WkgcTFtv')
|
||||
>>> print paste_to_delete
|
||||
Paste Removed
|
||||
|
||||
|
||||
@type api_dev_key: string
|
||||
@param api_dev_key: The API Developer Key of a registered U{http://pastebin.com} account.
|
||||
|
||||
@type api_user_key: string
|
||||
@param api_user_key: The API User Key of a U{http://pastebin.com} registered user.
|
||||
|
||||
@type api_paste_key: string
|
||||
@param api_paste_key: The Paste Key of the paste to be deleted (string after final / in U{http://pastebin.com} URL).
|
||||
|
||||
@rtype: string
|
||||
@returns: A successful deletion returns 'Paste Removed'.
|
||||
"""
|
||||
|
||||
# Valid api developer key
|
||||
argv = {'api_dev_key' : str(api_dev_key) }
|
||||
|
||||
# Requires pre-registered account
|
||||
if api_user_key is not None:
|
||||
argv['api_user_key'] = str(api_user_key)
|
||||
|
||||
# Key of the paste to be deleted.
|
||||
if api_paste_key is not None:
|
||||
argv['api_paste_key'] = str(api_paste_key)
|
||||
|
||||
# Valid API option - 'user_details' in this instance
|
||||
argv['api_option'] = str('delete')
|
||||
|
||||
|
||||
# lets try to read the URL that we've just built.
|
||||
request = urllib.urlopen(self._api_url, urllib.urlencode(argv))
|
||||
response = request_string.read()
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def user_details(self, api_dev_key, api_user_key):
|
||||
"""Return user details of the user specified by the api_user_key.
|
||||
|
||||
|
||||
Usage Example::
|
||||
>>> from pastebin import PastebinAPI
|
||||
>>> x = PastebinAPI()
|
||||
>>> details = x.user_details('453a994e0e2f1efae07f8759e59e075b',
|
||||
... 'c57a18e6c0ae228cd4bd16fe36da381a')
|
||||
>>> print details
|
||||
<user>
|
||||
<user_name>MonkeyPuzzle</user_name>
|
||||
<user_format_short>python</user_format_short>
|
||||
<user_expiration>N</user_expiration>
|
||||
<user_avatar_url>http://pastebin.com/i/guest.gif</user_avatar_url>
|
||||
<user_private>0</user_private>
|
||||
<user_website></user_website>
|
||||
<user_email>user@email.com</user_email>
|
||||
<user_location></user_location>
|
||||
<user_account_type>0</user_account_type>
|
||||
</user>
|
||||
|
||||
|
||||
@type api_dev_key: string
|
||||
@param api_dev_key: The API Developer Key of a registered U{http://pastebin.com} account.
|
||||
|
||||
@type api_user_key: string
|
||||
@param api_user_key: The API User Key of a U{http://pastebin.com} registered user.
|
||||
|
||||
@rtype: string
|
||||
@returns: Returns an XML string containing user information.
|
||||
"""
|
||||
|
||||
# Valid api developer key
|
||||
argv = {'api_dev_key' : str(api_dev_key) }
|
||||
|
||||
# Requires pre-registered account to generate an api_user_key
|
||||
# (see generate_user_key)
|
||||
if api_user_key is not None:
|
||||
argv['api_user_key'] = str(api_user_key)
|
||||
|
||||
# Valid API option - 'user_details' in this instance
|
||||
argv['api_option'] = str('userdetails')
|
||||
|
||||
# lets try to read the URL that we've just built.
|
||||
request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
|
||||
response = request_string.read()
|
||||
|
||||
# do some basic error checking here so we can gracefully handle any
|
||||
# errors we are likely to encounter
|
||||
if response.startswith(self._bad_request):
|
||||
raise PastebinError(response)
|
||||
|
||||
elif not response.startswith('<user>'):
|
||||
raise PastebinError(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def trending(self, api_dev_key):
|
||||
"""Returns the top trending paste details.
|
||||
|
||||
|
||||
Usage Example::
|
||||
>>> from pastebin import PastebinAPI
|
||||
>>> x = PastebinAPI()
|
||||
>>> details = x.trending('453a994e0e2f1efae07f8759e59e075b')
|
||||
>>> print details
|
||||
<paste>
|
||||
<paste_key>jjMRFDH6</paste_key>
|
||||
<paste_date>1333230838</paste_date>
|
||||
<paste_title></paste_title>
|
||||
<paste_size>6416</paste_size>
|
||||
<paste_expire_date>0</paste_expire_date>
|
||||
<paste_private>0</paste_private>
|
||||
<paste_format_long>None</paste_format_long>
|
||||
<paste_format_short>text</paste_format_short>
|
||||
<paste_url>http://pastebin.com/jjMRFDH6</paste_url>
|
||||
<paste_hits>6384</paste_hits>
|
||||
</paste>
|
||||
|
||||
Note: Returns multiple trending pastes, not just 1.
|
||||
|
||||
|
||||
@type api_dev_key: string
|
||||
@param api_dev_key: The API Developer Key of a registered U{http://pastebin.com} account.
|
||||
|
||||
|
||||
@rtype: string
|
||||
@return: Returns the string (XML formatted) containing the top trending pastes.
|
||||
"""
|
||||
|
||||
# Valid api developer key
|
||||
argv = {'api_dev_key' : str(api_dev_key) }
|
||||
|
||||
# Valid API option - 'trends' is returns trending pastes
|
||||
argv['api_option'] = str('trends')
|
||||
|
||||
# lets try to read the URL that we've just built.
|
||||
request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
|
||||
response = request_string.read()
|
||||
|
||||
# do some basic error checking here so we can gracefully handle any
|
||||
# errors we are likely to encounter
|
||||
if response.startswith(self._bad_request):
|
||||
raise PastebinError(response)
|
||||
|
||||
elif not response.startswith('<paste>'):
|
||||
raise PastebinError(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def pastes_by_user(self, api_dev_key, api_user_key, results_limit = None):
|
||||
"""Returns all pastes for the provided api_user_key.
|
||||
|
||||
|
||||
Usage Example::
|
||||
>>> from pastebin import PastebinAPI
|
||||
>>> x = PastebinAPI()
|
||||
>>> details = x.user_details('453a994e0e2f1efae07f8759e59e075b',
|
||||
... 'c57a18e6c0ae228cd4bd16fe36da381a',
|
||||
... 100)
|
||||
>>> print details
|
||||
<paste>
|
||||
<paste_key>DLiSspYT</paste_key>
|
||||
<paste_date>1332714730</paste_date>
|
||||
<paste_title>Pastebin.py - Python 3.2 Pastebin.com API</paste_title>
|
||||
<paste_size>25300</paste_size>
|
||||
<paste_expire_date>0</paste_expire_date>
|
||||
<paste_private>0</paste_private>
|
||||
<paste_format_long>Python</paste_format_long>
|
||||
<paste_format_short>python</paste_format_short>
|
||||
<paste_url>http://pastebin.com/DLiSspYT</paste_url>
|
||||
<paste_hits>70</paste_hits>
|
||||
</paste>
|
||||
|
||||
Note: Returns multiple pastes, not just 1.
|
||||
|
||||
|
||||
@type api_dev_key: string
|
||||
@param api_dev_key: The API Developer Key of a registered U{http://pastebin.com} account.
|
||||
|
||||
@type api_user_key: string
|
||||
@param api_user_key: The API User Key of a U{http://pastebin.com} registered user.
|
||||
|
||||
@type results_limit: number
|
||||
@param results_limit: The number of pastes to return between 1 - 1000.
|
||||
|
||||
@rtype: string
|
||||
@returns: Returns an XML string containing number of specified pastes by user.
|
||||
"""
|
||||
|
||||
# Valid api developer key
|
||||
argv = {'api_dev_key' : str(api_dev_key) }
|
||||
|
||||
# Requires pre-registered account
|
||||
if api_user_key is not None:
|
||||
argv['api_user_key'] = str(api_user_key)
|
||||
|
||||
# Number of results to return - between 1 & 1000, default = 50
|
||||
if results_limit is None:
|
||||
argv['api_results_limit'] = 50
|
||||
|
||||
if results_limit is not None:
|
||||
if results_limit < 1:
|
||||
argv['api_results_limit'] = 50
|
||||
elif results_limit > 1000:
|
||||
argv['api_results_limit'] = 1000
|
||||
else:
|
||||
argv['api_results_limit'] = int(results_limit)
|
||||
|
||||
# Valid API option - 'paste' is default for new paste
|
||||
argv['api_option'] = str('list')
|
||||
|
||||
# lets try to read the URL that we've just built.
|
||||
request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
|
||||
response = request_string.read()
|
||||
|
||||
# do some basic error checking here so we can gracefully handle any
|
||||
# errors we are likely to encounter
|
||||
if response.startswith(self._bad_request):
|
||||
raise PastebinError(response)
|
||||
|
||||
elif not response.startswith('<paste>'):
|
||||
raise PastebinError(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def generate_user_key(self, api_dev_key, username, password):
|
||||
"""Generate a user session key - needed for other functions.
|
||||
|
||||
|
||||
Usage Example::
|
||||
>>> from pastebin import PastebinAPI
|
||||
>>> x = PastebinAPI()
|
||||
>>> my_key = x.generate_user_key('453a994e0e2f1efae07f8759e59e075b',
|
||||
... 'MonkeyPuzzle',
|
||||
... '12345678')
|
||||
>>> print my_key
|
||||
c57a18e6c0ae228cd4bd16fe36da381a
|
||||
|
||||
|
||||
@type api_dev_key: string
|
||||
@param api_dev_key: The API Developer Key of a registered U{http://pastebin.com} account.
|
||||
|
||||
@type username: string
|
||||
@param username: The username of a registered U{http://pastebin.com} account.
|
||||
|
||||
@type password: string
|
||||
@param password: The password of a registered U{http://pastebin.com} account.
|
||||
|
||||
@rtype: string
|
||||
@returns: Session key (api_user_key) to allow authenticated interaction to the API.
|
||||
|
||||
"""
|
||||
# Valid api developer key
|
||||
argv = {'api_dev_key' : str(api_dev_key) }
|
||||
|
||||
# Requires pre-registered pastebin account
|
||||
if username is not None:
|
||||
argv['api_user_name'] = str(username)
|
||||
|
||||
# Requires pre-registered pastebin account
|
||||
if password is not None:
|
||||
argv['api_user_password'] = str(password)
|
||||
|
||||
# lets try to read the URL that we've just built.
|
||||
request_string = urllib.urlopen(self._api_login_url, urllib.urlencode(argv))
|
||||
response = request_string.read()
|
||||
|
||||
# do some basic error checking here so we can gracefully handle any errors we are likely to encounter
|
||||
if response.startswith(self._bad_request):
|
||||
raise PastebinError(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def paste(self, api_dev_key, api_paste_code,
|
||||
api_user_key = None, paste_name = None, paste_format = None,
|
||||
paste_private = None, paste_expire_date = None):
|
||||
|
||||
"""Submit a code snippet to Pastebin using the new API.
|
||||
|
||||
|
||||
Usage Example::
|
||||
>>> from pastebin import PastebinAPI
|
||||
>>> x = PastebinAPI()
|
||||
>>> url = x.paste('453a994e0e2f1efae07f8759e59e075b' ,
|
||||
... 'Snippet of code to paste goes here',
|
||||
... paste_name = 'title of paste',
|
||||
... api_user_key = 'c57a18e6c0ae228cd4bd16fe36da381a',
|
||||
... paste_format = 'python',
|
||||
... paste_private = 'unlisted',
|
||||
... paste_expire_date = '10M')
|
||||
>>> print url
|
||||
http://pastebin.com/tawPUgqY
|
||||
|
||||
|
||||
@type api_dev_key: string
|
||||
@param api_dev_key: The API Developer Key of a registered U{http://pastebin.com} account.
|
||||
|
||||
@type api_paste_code: string
|
||||
@param api_paste_code: The file or string to paste to body of the U{http://pastebin.com} paste.
|
||||
|
||||
@type api_user_key: string
|
||||
@param api_user_key: The API User Key of a U{http://pastebin.com} registered user.
|
||||
If none specified, paste is made as a guest.
|
||||
|
||||
@type paste_name: string
|
||||
@param paste_name: (Optional) Title of the paste.
|
||||
Default is to paste anonymously.
|
||||
|
||||
@type paste_format: string
|
||||
@param paste_format: (Optional) Programming language of the code being
|
||||
pasted. This enables syntax highlighting when reading the code in
|
||||
U{http://pastebin.com}. Default is no syntax highlighting (text is
|
||||
just text and not source code).
|
||||
|
||||
@type paste_private: string
|
||||
@param paste_private: (Optional) C{'public'} if the paste is public (visible
|
||||
by everyone), C{'unlisted'} if it's public but not searchable.
|
||||
C{'private'} if the paste is private and not searchable or indexed.
|
||||
The Pastebin FAQ (U{http://pastebin.com/faq}) claims
|
||||
private pastes are not indexed by search engines (aka Google).
|
||||
|
||||
@type paste_expire_date: str
|
||||
@param paste_expire_date: (Optional) Expiration date for the paste.
|
||||
Once past this date the paste is deleted automatically. Valid
|
||||
values are found in the L{PastebinAPI.paste_expire_date} class member.
|
||||
If not provided, the paste never expires.
|
||||
|
||||
@rtype: string
|
||||
@return: Returns the URL to the newly created paste.
|
||||
"""
|
||||
|
||||
|
||||
# Valid api developer key
|
||||
argv = {'api_dev_key' : str(api_dev_key) }
|
||||
|
||||
# Code snippet to submit
|
||||
if api_paste_code is not None:
|
||||
argv['api_paste_code'] = str(api_paste_code)
|
||||
|
||||
# Valid API option - 'paste' is default for new paste
|
||||
argv['api_option'] = str('paste')
|
||||
|
||||
# API User Key
|
||||
if api_user_key is not None:
|
||||
argv['api_user_key'] = str(api_user_key)
|
||||
elif api_user_key is None:
|
||||
argv['api_user_key'] = str('')
|
||||
|
||||
# Name of the poster
|
||||
if paste_name is not None:
|
||||
argv['api_paste_name'] = str(paste_name)
|
||||
|
||||
# Syntax highlighting
|
||||
if paste_format is not None:
|
||||
paste_format = str(paste_format).strip().lower()
|
||||
argv['api_paste_format'] = paste_format
|
||||
|
||||
# Is the snippet private?
|
||||
if paste_private is not None:
|
||||
if paste_private == 'public':
|
||||
argv['api_paste_private'] = int(0)
|
||||
elif paste_private == 'unlisted':
|
||||
argv['api_paste_private'] = int(1)
|
||||
elif paste_private == 'private':
|
||||
argv['api_paste_private'] = int(2)
|
||||
|
||||
# Expiration for the snippet
|
||||
if paste_expire_date is not None:
|
||||
paste_expire_date = str(paste_expire_date).strip().upper()
|
||||
argv['api_paste_expire_date'] = paste_expire_date
|
||||
|
||||
# lets try to read the URL that we've just built.
|
||||
request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
|
||||
response = request_string.read()
|
||||
|
||||
# do some basic error checking here so we can gracefully handle any
|
||||
# errors we are likely to encounter
|
||||
if response.startswith(self._bad_request):
|
||||
raise PastebinError(response)
|
||||
elif not response.startswith(self._prefix_url):
|
||||
raise PastebinError(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
######################################################
|
||||
|
||||
delete_paste = PastebinAPI.delete_paste
|
||||
user_details = PastebinAPI.user_details
|
||||
trending = PastebinAPI.trending
|
||||
pastes_by_user = PastebinAPI.pastes_by_user
|
||||
generate_user_key = PastebinAPI.generate_user_key
|
||||
paste = PastebinAPI.paste
|
||||
|
||||
######################################################
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -118,6 +118,7 @@ GIT_REPO = 'SickRage'
|
||||
GIT_USERNAME = None
|
||||
GIT_PASSWORD = None
|
||||
GIT_PATH = None
|
||||
GIT_AUTOISSUES = False
|
||||
|
||||
INIT_LOCK = Lock()
|
||||
started = False
|
||||
@ -524,7 +525,8 @@ def initialize(consoleLogging=True):
|
||||
USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, PROXY_INDEXERS, \
|
||||
AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \
|
||||
ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \
|
||||
ANIME_SPLIT_HOME, SCENE_DEFAULT, PLAY_VIDEOS, BACKLOG_DAYS, GIT_ORG, GIT_REPO, GIT_USERNAME, GIT_PASSWORD, gh
|
||||
ANIME_SPLIT_HOME, SCENE_DEFAULT, PLAY_VIDEOS, BACKLOG_DAYS, GIT_ORG, GIT_REPO, GIT_USERNAME, GIT_PASSWORD, \
|
||||
GIT_AUTOISSUES, gh
|
||||
|
||||
if __INITIALIZED__:
|
||||
return False
|
||||
@ -551,6 +553,16 @@ def initialize(consoleLogging=True):
|
||||
CheckSection(CFG, 'Pushbullet')
|
||||
CheckSection(CFG, 'Subtitles')
|
||||
|
||||
GIT_AUTOISSUES = bool(check_setting_int(CFG, 'General', 'git_autoissues', 0))
|
||||
|
||||
# git login info
|
||||
GIT_USERNAME = check_setting_str(CFG, 'General', 'git_username', '')
|
||||
GIT_PASSWORD = check_setting_str(CFG, 'General', 'git_password', '', censor_log=True)
|
||||
|
||||
# github api
|
||||
try:gh = Github(user_agent="SiCKRAGE").get_organization(GIT_ORG).get_repo(GIT_REPO)
|
||||
except:gh = None
|
||||
|
||||
# debugging
|
||||
DEBUG = bool(check_setting_int(CFG, 'General', 'debug', 0))
|
||||
|
||||
@ -565,16 +577,6 @@ def initialize(consoleLogging=True):
|
||||
# init logging
|
||||
logger.initLogging(consoleLogging=consoleLogging, fileLogging=fileLogging, debugLogging=DEBUG)
|
||||
|
||||
# git login info
|
||||
GIT_USERNAME = check_setting_str(CFG, 'General', 'git_username', '')
|
||||
GIT_PASSWORD = check_setting_str(CFG, 'General', 'git_password', '', censor_log=True)
|
||||
|
||||
# github api
|
||||
try:
|
||||
gh = Github(user_agent="SiCKRAGE").get_organization(GIT_ORG).get_repo(GIT_REPO)
|
||||
except:
|
||||
gh = None
|
||||
|
||||
# git reset on update
|
||||
GIT_RESET = bool(check_setting_int(CFG, 'General', 'git_reset', 0))
|
||||
|
||||
@ -1409,6 +1411,7 @@ def save_config():
|
||||
|
||||
# For passwords you must include the word `password` in the item_name and add `helpers.encrypt(ITEM_NAME, ENCRYPTION_VERSION)` in save_config()
|
||||
new_config['General'] = {}
|
||||
new_config['General']['git_autoissues'] = int(GIT_AUTOISSUES)
|
||||
new_config['General']['git_username'] = GIT_USERNAME
|
||||
new_config['General']['git_password'] = GIT_PASSWORD
|
||||
new_config['General']['git_reset'] = int(GIT_RESET)
|
||||
|
@ -18,14 +18,16 @@
|
||||
|
||||
from __future__ import with_statement
|
||||
import os
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import logging.handlers
|
||||
import threading
|
||||
import platform
|
||||
|
||||
import sickbeard
|
||||
from sickbeard import classes
|
||||
from github import Github
|
||||
from pastebin import PastebinAPI
|
||||
|
||||
# log levels
|
||||
ERROR = logging.ERROR
|
||||
@ -115,12 +117,15 @@ class Logger(object):
|
||||
message = meThread + u" :: " + msg
|
||||
|
||||
# pass exception information if debugging enabled
|
||||
if level == ERROR:
|
||||
kwargs["exc_info"] = 1
|
||||
classes.ErrorViewer.add(classes.UIError(message))
|
||||
|
||||
kwargs["exc_info"] = 1 if level == ERROR else 0
|
||||
self.logger.log(level, message, *args, **kwargs)
|
||||
|
||||
if level == ERROR:
|
||||
classes.ErrorViewer.add(classes.UIError(message))
|
||||
#if sickbeard.GIT_AUTOISSUES:
|
||||
# self.submit_errors()
|
||||
|
||||
def log_error_and_exit(self, error_msg, *args, **kwargs):
|
||||
self.log(error_msg, ERROR, *args, **kwargs)
|
||||
|
||||
@ -129,6 +134,52 @@ class Logger(object):
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
def submit_errors(self):
|
||||
if not (sickbeard.GIT_USERNAME and sickbeard.GIT_PASSWORD and len(classes.ErrorViewer.errors) > 0):
|
||||
return
|
||||
|
||||
title = "[APP SUBMITTED]: "
|
||||
|
||||
gh_org = sickbeard.GIT_ORG or 'SiCKRAGETV'
|
||||
gh_repo = 'sickrage-issues'
|
||||
|
||||
self.gh_issues = Github(login_or_token=sickbeard.GIT_USERNAME, password=sickbeard.GIT_PASSWORD,
|
||||
user_agent="SiCKRAGE").get_organization(gh_org).get_repo(gh_repo)
|
||||
|
||||
pastebin_url = None
|
||||
try:
|
||||
if os.path.isfile(logger.logFile):
|
||||
with ek.ek(open, logger.logFile) as f:
|
||||
data = f.readlines(50)
|
||||
pastebin_url = PastebinAPI().paste('f59b8e9fa1fc2d033e399e6c7fb09d19', data)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
for curError in sorted(classes.ErrorViewer.errors, key=lambda error: error.time, reverse=True)[:500]:
|
||||
message = u"### INFO\n"
|
||||
message += u"Python Version: **" + sys.version[:120] + "**\n"
|
||||
message += u"Operating System: **" + platform.platform() + "**\n"
|
||||
message += u"Branch: **" + sickbeard.BRANCH + "**\n"
|
||||
message += u"Commit: SiCKRAGETV/SickRage@" + sickbeard.CUR_COMMIT_HASH + "\n"
|
||||
if pastebin_url:
|
||||
message += u"Pastebin Log URL: " + pastebin_url + "\n"
|
||||
message += u"### ERROR\n"
|
||||
message += u"```\n"
|
||||
message += curError.message
|
||||
message += u"```\n"
|
||||
message += u"---\n"
|
||||
message += u"_STAFF NOTIFIED_: @SiCKRAGETV/owners @SiCKRAGETV/moderators"
|
||||
|
||||
issue = self.gh_issues.create_issue(title + curError.title, message)
|
||||
if issue:
|
||||
ui.notifications.message('Your issue ticket #%s was submitted successfully!' % issue.number)
|
||||
classes.ErrorViewer.clear()
|
||||
|
||||
except Exception as e:
|
||||
self.log(ex(e), logger.ERROR)
|
||||
|
||||
|
||||
class Wrapper(object):
|
||||
instance = Logger()
|
||||
|
||||
|
@ -24,11 +24,8 @@ import time
|
||||
import urllib
|
||||
import re
|
||||
import datetime
|
||||
import sys
|
||||
import platform
|
||||
|
||||
import sickbeard
|
||||
from github import Github
|
||||
from sickbeard import config, sab
|
||||
from sickbeard import clients
|
||||
from sickbeard import history, notifiers, processTV
|
||||
@ -3440,7 +3437,7 @@ class ConfigGeneral(Config):
|
||||
calendar_unprotected=None,
|
||||
fuzzy_dating=None, trim_zero=None, date_preset=None, date_preset_na=None, time_preset=None,
|
||||
indexer_timeout=None, play_videos=None, rootDir=None, theme_name=None,
|
||||
git_reset=None, git_username=None, git_password=None):
|
||||
git_reset=None, git_username=None, git_password=None, git_autoissues=None):
|
||||
|
||||
results = []
|
||||
|
||||
@ -3465,6 +3462,7 @@ class ConfigGeneral(Config):
|
||||
sickbeard.GIT_USERNAME = git_username
|
||||
sickbeard.GIT_PASSWORD = git_password
|
||||
sickbeard.GIT_RESET = config.checkbox_to_value(git_reset)
|
||||
sickbeard.GIT_AUTOISSUES = config.checkbox_to_value(git_autoissues)
|
||||
sickbeard.GIT_PATH = git_path
|
||||
sickbeard.GIT_REMOTE = git_remote
|
||||
sickbeard.CALENDAR_UNPROTECTED = config.checkbox_to_value(calendar_unprotected)
|
||||
@ -4643,7 +4641,7 @@ class ErrorLogs(WebRoot):
|
||||
def ErrorLogsMenu(self):
|
||||
menu = [
|
||||
{'title': 'Clear Errors', 'path': 'errorlogs/clearerrors/'},
|
||||
{'title': 'Submit Errors', 'path': 'errorlogs/submit_errors/', 'requires': self.haveGitHub},
|
||||
{'title': 'Submit Errors', 'path': 'errorlogs/submit_errors/', 'requires': self.haveErrors},
|
||||
]
|
||||
|
||||
return menu
|
||||
@ -4655,8 +4653,8 @@ class ErrorLogs(WebRoot):
|
||||
|
||||
return t.respond()
|
||||
|
||||
def haveGitHub(self):
|
||||
if sickbeard.GIT_USERNAME and sickbeard.GIT_PASSWORD:
|
||||
def haveErrors(self):
|
||||
if len(classes.ErrorViewer.errors) > 0:
|
||||
return True
|
||||
|
||||
def clearerrors(self):
|
||||
@ -4717,36 +4715,9 @@ class ErrorLogs(WebRoot):
|
||||
return t.respond()
|
||||
|
||||
def submit_errors(self):
|
||||
title = "[APP SUBMITTED]: "
|
||||
|
||||
gh_org = sickbeard.GIT_ORG or 'SiCKRAGETV'
|
||||
gh_repo = 'sickrage-issues'
|
||||
|
||||
self.gh_issues = Github(login_or_token=sickbeard.GIT_USERNAME, password=sickbeard.GIT_PASSWORD,
|
||||
user_agent="SiCKRAGE").get_organization(gh_org).get_repo(gh_repo)
|
||||
|
||||
try:
|
||||
for curError in sorted(classes.ErrorViewer.errors, key=lambda error: error.time, reverse=True)[:500]:
|
||||
title = title + curError.title
|
||||
|
||||
message = u"### INFO\n"
|
||||
message += u"Python Version: **" + sys.version[:120] + "**\n"
|
||||
message += u"Operating System: **" + platform.platform() + "**\n"
|
||||
message += u"Branch: **" + sickbeard.BRANCH + "**\n"
|
||||
message += u"Commit: SiCKRAGETV/SickRage@" + sickbeard.CUR_COMMIT_HASH + "\n"
|
||||
message += u"### ERROR\n"
|
||||
message += u"```\n"
|
||||
message += curError.message
|
||||
message += u"```\n"
|
||||
message += u"---\n"
|
||||
message += u"_STAFF NOTIFIED_: @SiCKRAGETV/owners @SiCKRAGETV/moderators"
|
||||
|
||||
issue = self.gh_issues.create_issue(title, message)
|
||||
if issue:
|
||||
ui.notifications.message('Your issue ticket #%s was submitted successfully!' % issue.number)
|
||||
classes.ErrorViewer.clear()
|
||||
|
||||
except Exception as e:
|
||||
logger.log(ex(e), logger.ERROR)
|
||||
if not (sickbeard.GIT_USERNAME and sickbeard.GIT_PASSWORD):
|
||||
logger.log(u'Please set your GitHub username and password in the config, unable to submit issue ticket to GitHub!')
|
||||
else:
|
||||
logger.submit_errors()
|
||||
|
||||
return self.redirect("/errorlogs/")
|
Loading…
Reference in New Issue
Block a user