def mail_admins_contact(request, subject, message, context, sender, to): """Send a message to the admins, as defined by the ADMINS setting.""" LOGGER.info( 'contact form from %s', sender, ) if not to and settings.ADMINS: to = [a[1] for a in settings.ADMINS] elif not settings.ADMINS: messages.error( request, _('Message could not be sent to administrator!') ) LOGGER.error( 'ADMINS not configured, can not send message!' ) return mail = EmailMultiAlternatives( '{0}{1}'.format(settings.EMAIL_SUBJECT_PREFIX, subject % context), message % context, to=to, headers={'Reply-To': sender}, ) mail.send(fail_silently=False) messages.success( request, _('Message has been sent to administrator.') )
def report_error(self, exc, request, message): """Wrapper for handling error situations""" extra = {'mt_url': self.request_url, 'mt_params': self.request_params} report_error(exc, request, extra, prefix='Machine translation error') LOGGER.error(message, self.name) LOGGER.info( 'Last URL: %s, params: %s', extra['mt_url'], extra['mt_params'] )
def get_notification_email(language, email, notification, context=None, info=None): """Render notification email.""" context = context or {} headers = {} LOGGER.info( 'sending notification %s on %s to %s', notification, info, email ) with override('en' if language is None else language): # Template name context['subject_template'] = 'mail/{0}_subject.txt'.format( notification ) context['LANGUAGE_CODE'] = get_language() context['LANGUAGE_BIDI'] = get_language_bidi() # Adjust context context['current_site_url'] = get_site_url() context['site_title'] = settings.SITE_TITLE # Render subject subject = render_to_string( context['subject_template'], context ).strip() # Render body html_body = render_to_string( 'mail/{0}.html'.format(notification), context ) body = html2text(html_body) # Define headers headers['Auto-Submitted'] = 'auto-generated' headers['X-AutoGenerated'] = 'yes' headers['Precedence'] = 'bulk' headers['X-Mailer'] = 'Weblate {0}'.format(VERSION) # List of recipients if email == 'ADMINS': emails = [a[1] for a in settings.ADMINS] else: emails = [email] # Return the mail content return { 'subject': subject, 'body': body, 'to': emails, 'headers': headers, 'html_body': html_body, }
def clean_captcha(self): """ Validation for captcha. """ if self.tampering or not self.captcha.validate(self.cleaned_data["captcha"]): raise forms.ValidationError(_("Please check your math and try again.")) mail = self.cleaned_data.get("email", "NONE") LOGGER.info("Passed captcha for %s (%s = %s)", mail, self.captcha.question, self.cleaned_data["captcha"])
def send_immediate(self, language, email, change): with override('en' if language is None else language): context = self.get_context(change) subject = self.render_template('_subject.txt', context) context['subject'] = subject LOGGER.info( 'sending notification %s on %s to %s', self.get_name(), context['component'], email, ) self.send( email, subject, self.render_template('.html', context), self.get_headers(context), )
def clean_captcha(self): """Validation for captcha.""" if (self.fresh or not self.captcha.validate(self.cleaned_data['captcha'])): raise forms.ValidationError( _('Please check your math and try again.') ) mail = self.cleaned_data.get('email', 'NONE') LOGGER.info( 'Passed captcha for %s (%s = %s)', mail, self.captcha.question, self.cleaned_data['captcha'] )
def send_digest(self, language, email, changes): with override('en' if language is None else language): context = self.get_context() context['changes'] = changes subject = self.render_template( '_subject.txt', context, digest=True ) context['subject'] = subject LOGGER.info( 'sending digest notification %s on %d changes to %s', self.get_name(), len(changes), email, ) self.send( email, subject, self.render_template('.html', context, digest=True), self.get_headers(context), )
def mail_admins_contact(request, subject, message, context, sender): """ Sends a message to the admins, as defined by the ADMINS setting. """ LOGGER.info("contact form from %s", sender) if not settings.ADMINS: messages.error(request, _("Message could not be sent to administrator!")) LOGGER.error("ADMINS not configured, can not send message!") return mail = EmailMultiAlternatives( "%s%s" % (settings.EMAIL_SUBJECT_PREFIX, subject % context), message % context, to=[a[1] for a in settings.ADMINS], headers={"Reply-To": sender}, ) mail.send(fail_silently=False) messages.success(request, _("Message has been sent to administrator."))
def clean_captcha(self): """Validation for CAPTCHA.""" if (self.fresh or not self.captcha.validate(self.cleaned_data['captcha'])): self.generate_captcha() rotate_token(self.request) raise forms.ValidationError( _('Please check your math and try again with new expression.') ) if self.form.is_valid(): mail = self.form.cleaned_data['email'] else: mail = 'NONE' LOGGER.info( 'Passed captcha for %s (%s = %s)', mail, self.captcha.question, self.cleaned_data['captcha'] )
def clean_captcha(self): ''' Validation for captcha. ''' if (self.tampering or not self.captcha.validate(self.cleaned_data['captcha'])): raise forms.ValidationError( _('Please check your math and try again.') ) if 'email' in self.cleaned_data: mail = self.cleaned_data['email'] else: mail = 'NONE' LOGGER.info( 'Passed captcha for %s (%s = %s)', mail, self.captcha.question, self.cleaned_data['captcha'] )
def get_notification_email(language, email, notification, translation_obj=None, context=None, headers=None, user=None, info=None): """Render notification email.""" context = context or {} headers = headers or {} references = None if 'unit' in context: unit = context['unit'] references = '{0}/{1}/{2}/{3}'.format( unit.translation.component.project.slug, unit.translation.component.slug, unit.translation.language.code, unit.id) if references is not None: references = '<{0}@{1}>'.format(references, get_site_domain()) headers['In-Reply-To'] = references headers['References'] = references if info is None: info = force_text(translation_obj) LOGGER.info('sending notification %s on %s to %s', notification, info, email) with django_translation.override('en' if language is None else language): # Template name context['subject_template'] = 'mail/{0}_subject.txt'.format( notification) context['LANGUAGE_CODE'] = django_translation.get_language() context['LANGUAGE_BIDI'] = django_translation.get_language_bidi() # Adjust context context['current_site_url'] = get_site_url() if translation_obj is not None: context['translation'] = translation_obj context['translation_url'] = get_site_url( translation_obj.get_absolute_url()) context['site_title'] = settings.SITE_TITLE # Render subject subject = render_to_string(context['subject_template'], context).strip() # Render body body = render_to_string('mail/{0}.txt'.format(notification), context) html_body = render_to_string('mail/{0}.html'.format(notification), context) # Define headers headers['Auto-Submitted'] = 'auto-generated' headers['X-AutoGenerated'] = 'yes' headers['Precedence'] = 'bulk' headers['X-Mailer'] = 'Weblate {0}'.format(VERSION) # Reply to header if user is not None: headers['Reply-To'] = user.email # List of recipients if email == 'ADMINS': emails = [a[1] for a in settings.ADMINS] else: emails = [email] # Return the mail content return { 'subject': subject, 'body': body, 'to': emails, 'headers': headers, 'html_body': html_body, }
def vcs_service_hook(request, service): """Shared code between VCS service hooks. Currently used for bitbucket_hook, github_hook and gitlab_hook, but should be usable for other VCS services (Google Code, custom coded sites, etc.) too. """ # We support only post methods if not settings.ENABLE_HOOKS: return HttpResponseNotAllowed(()) # Check if we got payload try: data = parse_hook_payload(request) except (ValueError, KeyError, UnicodeError): return HttpResponseBadRequest('Could not parse JSON payload!') # Get service helper hook_helper = HOOK_HANDLERS[service] # Send the request data to the service handler. try: service_data = hook_helper(data) except Exception as error: LOGGER.error('failed to parse service %s data', service) report_error(error, sys.exc_info()) return HttpResponseBadRequest('Invalid data in json payload!') # This happens on ping request upon installation if service_data is None: return hook_response('Hook working') # Log data service_long_name = service_data['service_long_name'] repos = service_data['repos'] repo_url = service_data['repo_url'] branch = service_data['branch'] full_name = service_data['full_name'] # Generate filter spfilter = Q(repo__in=repos) | Q(repo__iendswith=full_name) # We need to match also URLs which include username and password for repo in repos: if not repo.startswith('https://'): continue spfilter = spfilter | ( Q(repo__startswith='https://') & Q(repo__endswith='@{0}'.format(repo[8:])) ) all_components = Component.objects.filter(spfilter) if branch is not None: all_components = all_components.filter(branch=branch) components = all_components.filter(project__enable_hooks=True) LOGGER.info( 'received %s notification on repository %s, branch %s, ' '%d matching components, %d to process', service_long_name, repo_url, branch, all_components.count(), components.count(), ) # Trigger updates updates = 0 for obj in components: updates += 1 LOGGER.info( '%s notification will update %s', service_long_name, obj ) perform_update(obj) if updates == 0: return hook_response('No matching repositories found!', 'failure') return hook_response('Update triggered: {}'.format( ', '.join([obj.log_prefix for obj in components]) ))
def vcs_service_hook(request, service): ''' Shared code between VCS service hooks. Currently used for bitbucket_hook, github_hook and gitlab_hook, but should be usable for other VCS services (Google Code, custom coded sites, etc.) too. ''' # Check for enabled hooks if appsettings.ENABLE_HOOKS: allowed_methods = ('POST', ) else: allowed_methods = () # We support only post methods if not appsettings.ENABLE_HOOKS or request.method not in allowed_methods: return HttpResponseNotAllowed(allowed_methods) # Check if we got payload try: # GitLab sends json as application/json if request.META['CONTENT_TYPE'] == 'application/json': data = json.loads(request.body) # Bitbucket and GitHub sends json as x-www-form-data else: data = json.loads(request.POST['payload']) except (ValueError, KeyError): return HttpResponseBadRequest('Could not parse JSON payload!') # Get service helper if service not in HOOK_HANDLERS: LOGGER.error('service %s is not supported', service) return HttpResponseBadRequest('invalid service') hook_helper = HOOK_HANDLERS[service] # Send the request data to the service handler. try: service_data = hook_helper(data) except KeyError: LOGGER.error('failed to parse service %s data', service) return HttpResponseBadRequest('Invalid data in json payload!') # Log data service_long_name = service_data['service_long_name'] repos = service_data['repos'] repo_url = service_data['repo_url'] branch = service_data['branch'] LOGGER.info('received %s notification on repository %s, branch %s', service_long_name, repo_url, branch) subprojects = SubProject.objects.filter(repo__in=repos) if branch is not None: subprojects = subprojects.filter(branch=branch) # Trigger updates for obj in subprojects: if not obj.project.enable_hooks: continue LOGGER.info('%s notification will update %s', service_long_name, obj) perform_update(obj) return hook_response()
def log_info(self, msg, *args): return LOGGER.info( self.log_prefix + msg, *args )
def log(self, *args): if self.component: self.component.log_info(*args) else: LOGGER.info(*args)
def vcs_service_hook(request, service): """Shared code between VCS service hooks. Currently used for bitbucket_hook, github_hook and gitlab_hook, but should be usable for other VCS services (Google Code, custom coded sites, etc.) too. """ # We support only post methods if not settings.ENABLE_HOOKS: return HttpResponseNotAllowed(()) # Check if we got payload try: data = parse_hook_payload(request) except (ValueError, KeyError): return HttpResponseBadRequest("Could not parse JSON payload!") if not data: return HttpResponseBadRequest("Invalid data in json payload!") # Get service helper hook_helper = HOOK_HANDLERS[service] # Send the request data to the service handler. try: service_data = hook_helper(data, request) except Exception: LOGGER.error("failed to parse service %s data", service) report_error() return HttpResponseBadRequest("Invalid data in json payload!") # This happens on ping request upon installation if service_data is None: return hook_response("Hook working", status=201) # Log data service_long_name = service_data["service_long_name"] repos = service_data["repos"] repo_url = service_data["repo_url"] branch = service_data["branch"] full_name = service_data["full_name"] # Generate filter spfilter = Q(repo__in=repos) | Q(repo__iendswith=full_name) # We need to match also URLs which include username and password for repo in repos: if repo.startswith("http://"): spfilter = spfilter | (Q(repo__startswith="http://") & Q(repo__endswith="@{0}".format(repo[7:]))) elif repo.startswith("https://"): spfilter = spfilter | (Q(repo__startswith="https://") & Q(repo__endswith="@{0}".format(repo[8:]))) all_components = Component.objects.filter(spfilter) if branch is not None: all_components = all_components.filter(branch=branch) components = all_components.filter(project__enable_hooks=True) LOGGER.info( "received %s notification on repository %s, branch %s, " "%d matching components, %d to process, %d linked", service_long_name, repo_url, branch, all_components.count(), components.count(), Component.objects.filter(linked_component__in=components).count(), ) # Trigger updates updates = 0 for obj in components: updates += 1 LOGGER.info("%s notification will update %s", service_long_name, obj) Change.objects.create(component=obj, action=Change.ACTION_HOOK, details=service_data) perform_update.delay("Component", obj.pk) if updates == 0: return hook_response("No matching repositories found!", "failure", status=202) return hook_response("Update triggered: {}".format(", ".join( obj.full_slug for obj in components)))
def log_info(self, msg, *args): self.log_hook('INFO', msg, *args) return LOGGER.info(': '.join((self.full_slug, msg)), *args)
def log_info(self, msg, *args): return LOGGER.info(self.log_prefix + msg, *args)
def vcs_service_hook(request, service): """Shared code between VCS service hooks. Currently used for bitbucket_hook, github_hook and gitlab_hook, but should be usable for other VCS services (Google Code, custom coded sites, etc.) too. """ # We support only post methods if not settings.ENABLE_HOOKS: return HttpResponseNotAllowed(()) # Check if we got payload try: data = parse_hook_payload(request) except (ValueError, KeyError, UnicodeError): return HttpResponseBadRequest('Could not parse JSON payload!') if not data: return HttpResponseBadRequest('Invalid data in json payload!') # Get service helper hook_helper = HOOK_HANDLERS[service] # Send the request data to the service handler. try: service_data = hook_helper(data) except Exception as error: LOGGER.error('failed to parse service %s data', service) report_error(error, request) return HttpResponseBadRequest('Invalid data in json payload!') # This happens on ping request upon installation if service_data is None: return hook_response('Hook working') # Log data service_long_name = service_data['service_long_name'] repos = service_data['repos'] repo_url = service_data['repo_url'] branch = service_data['branch'] full_name = service_data['full_name'] # Generate filter spfilter = Q(repo__in=repos) | Q(repo__iendswith=full_name) # We need to match also URLs which include username and password for repo in repos: if not repo.startswith('https://'): continue spfilter = spfilter | (Q(repo__startswith='https://') & Q(repo__endswith='@{0}'.format(repo[8:]))) all_components = Component.objects.filter(spfilter) if branch is not None: all_components = all_components.filter(branch=branch) components = all_components.filter(project__enable_hooks=True) LOGGER.info( 'received %s notification on repository %s, branch %s, ' '%d matching components, %d to process', service_long_name, repo_url, branch, all_components.count(), components.count(), ) # Trigger updates updates = 0 for obj in components: updates += 1 LOGGER.info('%s notification will update %s', service_long_name, obj) perform_update.delay('Component', obj.pk) if updates == 0: return hook_response('No matching repositories found!', 'failure') return hook_response('Update triggered: {}'.format(', '.join( [obj.full_slug for obj in components])))
def log_info(self, msg, *args): self.log_hook('INFO', msg, *args) return LOGGER.info( ': '.join((self.full_slug, msg)), *args )
def get_notification_email(language, email, notification, translation_obj=None, context=None, headers=None, user=None, info=None): """Render notification email.""" cur_language = django_translation.get_language() context = context or {} headers = headers or {} references = None if 'unit' in context: unit = context['unit'] references = '{0}/{1}/{2}/{3}'.format( unit.translation.subproject.project.slug, unit.translation.subproject.slug, unit.translation.language.code, unit.id) if references is not None: references = '<{0}@{1}>'.format(references, get_site_domain()) headers['In-Reply-To'] = references headers['References'] = references try: if info is None: info = force_text(translation_obj) LOGGER.info('sending notification %s on %s to %s', notification, info, email) # Load user language if language is not None: django_translation.activate(language) # Template name context['subject_template'] = 'mail/{0}_subject.txt'.format( notification) # Adjust context context['current_site_url'] = get_site_url() if translation_obj is not None: context['translation'] = translation_obj context['translation_url'] = get_site_url( translation_obj.get_absolute_url()) context['site_title'] = settings.SITE_TITLE # Render subject subject = render_to_string(context['subject_template'], context).strip() # Render body body = render_to_string('mail/{0}.txt'.format(notification), context) html_body = render_to_string('mail/{0}.html'.format(notification), context) # Define headers headers['Auto-Submitted'] = 'auto-generated' headers['X-AutoGenerated'] = 'yes' headers['Precedence'] = 'bulk' headers['X-Mailer'] = 'Weblate {0}'.format(VERSION) # Reply to header if user is not None: headers['Reply-To'] = user.email # List of recipients if email == 'ADMINS': emails = [a[1] for a in settings.ADMINS] else: emails = [email] # Create message email = EmailMultiAlternatives( settings.EMAIL_SUBJECT_PREFIX + subject, body, to=emails, headers=headers, ) email.attach_alternative(html_body, 'text/html') # Return the mail return email finally: django_translation.activate(cur_language)
def log_info(self, msg, *args): return LOGGER.info(": ".join((self.log_prefix, msg)), *args)
def log_info(self, msg, *args): self.log_hook("INFO", msg, *args) return LOGGER.info(": ".join((self.full_slug, msg)), *args)
def log_info(self, msg, *args): return LOGGER.info( ': '.join((self.full_slug, msg)), *args )
def report_error(self, exc, message): """Wrapper for handling error situations""" report_error(exc, prefix='Machinery error') LOGGER.error(message, self.name) LOGGER.info('Last URL: %s, params: %s', self.request_url, self.request_params)
def vcs_service_hook(request, service): ''' Shared code between VCS service hooks. Currently used for bitbucket_hook, github_hook and gitlab_hook, but should be usable for other VCS services (Google Code, custom coded sites, etc.) too. ''' # Check for enabled hooks if appsettings.ENABLE_HOOKS: allowed_methods = ('POST',) else: allowed_methods = () # We support only post methods if not appsettings.ENABLE_HOOKS or request.method not in allowed_methods: return HttpResponseNotAllowed(allowed_methods) # Check if we got payload try: # GitLab sends json as application/json if request.META['CONTENT_TYPE'] == 'application/json': data = json.loads(request.body) # Bitbucket and GitHub sends json as x-www-form-data else: data = json.loads(request.POST['payload']) except (ValueError, KeyError): return HttpResponseBadRequest('Could not parse JSON payload!') # Get service helper if service not in HOOK_HANDLERS: LOGGER.error('service %s is not supported', service) return HttpResponseBadRequest('invalid service') hook_helper = HOOK_HANDLERS[service] # Send the request data to the service handler. try: service_data = hook_helper(data) except KeyError: LOGGER.error('failed to parse service %s data', service) return HttpResponseBadRequest('Invalid data in json payload!') # Log data service_long_name = service_data['service_long_name'] repos = service_data['repos'] repo_url = service_data['repo_url'] branch = service_data['branch'] LOGGER.info( 'received %s notification on repository %s, branch %s', service_long_name, repo_url, branch ) subprojects = SubProject.objects.filter(repo__in=repos) if branch is not None: subprojects = subprojects.filter(branch=branch) # Trigger updates for obj in subprojects: if not obj.project.enable_hooks: continue LOGGER.info( '%s notification will update %s', service_long_name, obj ) perform_update(obj) return hook_response()
def log_info(self, msg, *args): return LOGGER.info( ': '.join((self.log_prefix, msg)), *args )
def get_notification_email(language, email, notification, translation_obj=None, context=None, headers=None, user=None, info=None): ''' Renders notification email. ''' cur_language = django_translation.get_language() context = context or {} headers = headers or {} references = None if 'unit' in context: unit = context['unit'] references = '{0}/{1}/{2}/{3}'.format( unit.translation.subproject.project.slug, unit.translation.subproject.slug, unit.translation.language.code, unit.id ) if references is not None: references = '<{0}@{1}>'.format(references, get_site_domain()) headers['In-Reply-To'] = references headers['References'] = references try: if info is None: info = translation_obj.__unicode__() LOGGER.info( 'sending notification %s on %s to %s', notification, info, email ) # Load user language if language is not None: django_translation.activate(language) # Template name context['subject_template'] = 'mail/{}_subject.txt'.format( notification ) # Adjust context context['current_site_url'] = get_site_url() if translation_obj is not None: context['translation'] = translation_obj context['translation_url'] = get_site_url( translation_obj.get_absolute_url() ) context['site_title'] = SITE_TITLE # Render subject subject = render_to_string( context['subject_template'], context ).strip() # Render body body = render_to_string( 'mail/{}.txt'.format(notification), context ) html_body = render_to_string( 'mail/{}.html'.format(notification), context ) # Define headers headers['Auto-Submitted'] = 'auto-generated' headers['X-AutoGenerated'] = 'yes' headers['Precedence'] = 'bulk' headers['X-Mailer'] = 'Weblate {}'.format(VERSION) # Reply to header if user is not None: headers['Reply-To'] = user.email # List of recipients if email == 'ADMINS': emails = [a[1] for a in settings.ADMINS] else: emails = [email] # Create message email = EmailMultiAlternatives( settings.EMAIL_SUBJECT_PREFIX + subject, body, to=emails, headers=headers, ) email.attach_alternative( html_body, 'text/html' ) # Return the mail return email finally: django_translation.activate(cur_language)
def log_info(self, msg, *args): return LOGGER.info(': '.join((self.full_slug, msg)), *args)