#!/usr/bin/env python3
# vim: sw=2:ts=2:noet
# -*- coding: utf-8 -*-
#
####  Assemble the Undead				#####
#
#  This is a script that serves the purpose of creating a wikipage and
#  send out a mail, when there are issues in redmine with a certain
#  status. It's supposed to be running as a crownjob.
#  
####	Arguments:						#####
#
#	--nomail		do not send a mail
#	--nowiki		don't create a wiki page
#	--verbose, -v	output everything
#	--quiet, -q		only print errors
#
#
####	Copyright 2020  <cpp@zom.bi>	#####
#  
#  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, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#  
#  

import sys, requests, datetime, smtplib, os, re
from email.mime.text import MIMEText
from email.utils import formatdate

# Redmine config
redmine_url			= os.getenv('REDMINE_URL')
redmine_api_key	= os.getenv('REDMINE_API_KEY')

## Mediawiki config
mediawiki_url		= os.getenv('MEDIAWIKI_URL')
# should be Bot credentials, that can be created on Special:BotPasswords
mediawiki_username	= os.getenv('MEDIAWIKI_USERNAME')
mediawiki_botpassword=os.getenv('MEDIAWIKI_BOTPASSWORD')
smtp_recipients = re.split(' ',os.getenv('SMTP_RECIPIENTS'))
# smtp config
smtp_host			= os.getenv('SMTP_HOST')
smtp_port			= os.getenv('SMTP_PORT')
smtp_from			= os.getenv('SMTP_FROM')
smtp_user			  = os.getenv('SMTP_USER')
smtp_password		= os.getenv('SMTP_PASSWORD')
mail_subject		= os.getenv('MAIL_SUBJECT')
mail_header			= os.getenv('MAIL_HEADER').replace("\\n","\n")
mail_footer			= os.getenv('MAIL_FOOTER').replace("\\n","\n")

def main(args):

	assembly_date		= str(datetime.date.today() +\
		datetime.timedelta(datetime.date.today().weekday() % 7 + 1))
	requires_assembly	= redmine_get_requires_assembly_id()
	log(1,"Assembly topics:\n")
	issues = redmine_get_issues(requires_assembly)
	if not issues:
		# do nothing, if there are no issues requiring an assembly.
		log(1,"No issue requires an assembly.\n exiting.")
		return 0
	mediawiki_page = {'title': 'Zombi:Assembly '+assembly_date,\
		'content':'{{plenum|Datum=' + assembly_date + '}}'}
	mediawiki_page['content'] = '=Issues from redmine that require an assembly=\n'
	for issue in issues:
		# Append every issue to the page content
		log(1,issue['subject'])
		mediawiki_page['content']= mediawiki_page['content'] + '==' +\
			issue["subject"]+ '==\n\n' + 'Author: ' +\
			issue['author']['name'] + '\n\n' + issue['description'] + '\n'
	log(1,'')
	if '--no-wiki' in args:
		log(1,"'--no-wiki' argument given, so no wiki page has been created.")
	else:
		mediawiki_session	= mediawiki_login()
		mediawiki_create(mediawiki_session, mediawiki_page)
	
	# Send out the mail
	if '--no-mail' in args:
		log(1,"'--no-mail' argument given, so no mails have been sent.")
	else:
		smtp_send(mediawiki_page['content'])
	return 0

def smtp_send(content):
	smtp_server = smtplib.SMTP_SSL(host=smtp_host,port=smtp_port)
	if loglevel == 2:
		smtp_server.set_debuglevel(1)
	smtp_server.connect(host=smtp_host)
	smtp_server.login(user=smtp_user,password=smtp_password)
	mail_message = MIMEText(mail_header + \
		content + mail_footer)
	mail_message['Subject']	= mail_subject
	mail_message['From']	= smtp_from
	mail_message['Date']	= formatdate()
	for recipient in smtp_recipients:
		mail_message['To']	= recipient
		smtp_server.sendmail(from_addr=smtp_from,\
			to_addrs=recipient,msg=mail_message.as_string())
		del mail_message['To']
	smtp_server.quit()

def redmine_request(path):
	request = requests.get(redmine_url + path,
		headers={
			'X-Redmine-API-Key': redmine_api_key
		}
	)
	return request.json()

def redmine_get_requires_assembly_id():
	data = redmine_request('/issue_statuses.json')
	requires_assembly = next(filter(lambda x: x['name'] == \
		'Requires Assembly',data['issue_statuses']))['id']
	return requires_assembly

def redmine_get_issues(state):
	tickets = redmine_request('/issues.json?status_id=' + str(state))
	return tickets['issues']

def mediawiki_login():
	log(2,"Logging into mediawiki")
	s = requests.Session()
	t_request	= s.post(mediawiki_url +
		"/api.php?action=query&format=json&meta=tokens&type=login")
	token	= t_request.json()["query"]["tokens"]["logintoken"]
	response= s.post(mediawiki_url + '/api.php?action=login&format=json',
		data={
			'lgname': mediawiki_username,
			'lgpassword': mediawiki_botpassword,
			'lgtoken': token
		}
	).json()
	if 'error' in response:
		log(0,'Logging into mediawiki failed, errorcode: '+ response['error']['code'])
		raise ValueError(response["error"])
	else:
		log(2,response['login']['result'])
		return s
def mediawiki_create(s,page):
	log(2,'Creating Wiki page "'+ page['title'] + '"')
	t_request	= s.post(mediawiki_url +
		'/api.php?action=query&format=json&meta=tokens')
	token		= t_request.json()["query"]["tokens"]["csrftoken"]
	response = s.post(mediawiki_url + '/api.php?action=edit&format=json' \
		+ '&title=' + page['title'] + '&text=',
		data = {
			'token': token,
			'text' : page['content']
		}
	).json()
	if 'error' in response:
		log(0,'Creating page failed, errorcode: '+ response['error']['code'])
		raise ValueError(response["error"])
	else:
		log(2,response['edit']['result'])
		return 0

def log(l,log_message):
	# 0 - only print errors (-q)
	# 1 - normal operation
	# 2 - print everything

	if l<=loglevel:
		print(log_message)

if __name__ == '__main__':
	if '-q' in sys.argv or '--quiet' in sys.argv:
		loglevel = 0
	elif '-v' in sys.argv or '--verbose' in sys.argv:
		loglevel = 2
	else:
		loglevel = 1
	sys.exit(main(sys.argv))