Google Pay for Passes send notification - google-pay

import os
import service
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account
# Path to service account key file obtained from Google CLoud Console
service_account_file = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "vdelodevepoper-bc77807e143f.json")
# Issuer ID obtained from Google Pay Business Console.
# Developer defined ID for the wallet class.
issuer_id = "3388000000022131935"
class_id = "6666"
resourceId = issuer_id + '.' + class_id
# [START auth]
credentials = service_account.Credentials.from_service_account_file(service_account_file, scopes=[
"https://www.googleapis.com/auth/wallet_object.issuer"])
http_client = AuthorizedSession(credentials)
# [END auth]
# Get the specific Offer Object
offer_object = service.offerobject().get(resourceId=resourceId)
# Update the version, validTimeInterval.end, and add a message
offer_object['version'] = str(int(offer_object['version']) + 1)
offer_object['validTimeInterval'] = {
'start': {'date': ''},
'end': {'date': ''}
}
# Get the current messages
messages = offer_object['messages']
# Define new message
message = {
'header': 'Test notification',
'body': 'Your offer has been extended!',
'kind': 'walletobjects#walletObjectMessage'
}
# Add the new message about updates to the Offer Object
messages.append(message)
offer_object['messages'] = messages
# Update the Offer Object
api_request = service.offerobject().update(resourceId=resourceId, body=offer_object)
api_response = api_request.execute()
I don't understand what is used offer_object = service.offerobject().get(resourceId=resourceId)
service.offerobject(), which libraries should be included?
When I run my code, I get an error:
offer_object = service.offerobject().get(resourceId=resourceId)
AttributeError: module 'service' has no attribute 'offerobject'

Related

Google people API returning empty / no results in Python

I'm trying to read contacts from my person gmail account and the instructions provided by Google from the People API is returning an empty list. I'm not sure why. I've tried another solution from a few years ago, but that doens't seem to work. I've pasted my code below. Any help troubleshooting this is appreciated!
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/contacts.readonly']
from google.oauth2 import service_account
SERVICE_ACCOUNT_FILE = '<path name hidden>.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
def main():
#Shows basic usage of the People API.
#Prints the name of the first 10 connections.
creds = None
service = build('people', 'v1', credentials=credentials)
# Call the People API
print('List 10 connection names')
results = service.people().connections().list(
resourceName='people/me',
pageSize=10,
personFields='names,emailAddresses').execute()
connections = results.get('connections', [])
request = service.people().searchContacts(pageSize=10, query="A", readMask="names")
results = service.people().connections().list(resourceName='people/me',personFields='names,emailAddresses',fields='connections,totalItems,nextSyncToken').execute()
for i in results:
print ('result', i)
for person in connections:
names = person.get('names', [])
if names:
name = names[0].get('displayName')
print(name)
if __name__ == '__main__':
main()

How can I remove messages from an ActiveMQ queue using Python?

I have an ActiveMQ queue which has several messages that were sent using persistent set to true. When I create a subscriber in Python to read the queue, I get all of the messages in the queue. The next time I open the subscriber, I get all of the same messages. I adjusted the code that writes to the queue to set persistent to false, but the message remains in the queue. Have I neglected to send an acknowledgement?
The code is written using Python 2.7 because that's what our customer is using. I'd love to upgrade them, but I don't have the time.
Here's the script that reads the queue:
import socket
import threading
import xml.etree.ElementTree as etree
from xml.dom import minidom # for pretty printing
# import SampleXML
import sys
import os
import math
import time
from time import monotonic
import string
import stomp # for queue support
import platform
class ConnectionListener(stomp.ConnectionListener):
def __init__(self, connection):
self.connection = connection
print ("Listener created")
def on_message(self, message):
print ("Received message with body ") + message.body
class Reader:
def __init__(self):
pass
def ConnectToQueue(self):
#For Production
user = os.getenv("ACTIVEMQ_USER") or "worthington"
#user = os.getenv("ACTIVEMQ_USER") or "worthington_test"
password = os.getenv("ACTIVEMQ_PASSWORD") or "level3"
host = os.getenv("ACTIVEMQ_HOST") or "localhost"
port = os.getenv("ACTIVEMQ_PORT") or 61613
# destination = sys.argv[1:2] or ["/topic/event"]
# destination = destination[0]
dest = "from_entec_test"
#For Production
# dest = "from_entec"
try:
conn = stomp.Connection10(host_and_ports = [(host, port)])
conn.set_listener('message', ConnectionListener(conn))
# conn.start()
# subscribe_id = '-'.join(map(str, (platform.node(), os.getppid(), os.getpid())))
conn.connect(login=user,passcode=password)
subscribe_id = "Queue Test Listener"
conn.subscribe(destination=dest, id=subscribe_id, ack='client-individual')
conn.unsubscribe(id=subscribe_id)
conn.disconnect()
except Exception as error:
reason = str(error)
print("Exception when readig data from queue: " + str(error))
pass
if __name__ == "__main__" :
try:
UploadData = Reader()
UploadData.ConnectToQueue()
print ("Reader finished.")
except Exception as Value:
reason = str(Value)
pass
And here's the code that writes to it:
import socket
import threading
import xml.etree.ElementTree as etree
from xml.dom import minidom # for pretty printing
# import SampleXML
import sys
import os
import math
import time
from time import monotonic
import string
import stomp # for queue support
import platform
class ConnectionListener(stomp.ConnectionListener):
def __init__(self, connection):
self.connection = connection
print "Listener created"
def on_message(self, message):
print "Received message with body " + message.body
class UploadData:
def __init__(self):
pass
def ConnectToQueue(self):
#For Production
user = os.getenv("ACTIVEMQ_USER") or "worthington"
#user = os.getenv("ACTIVEMQ_USER") or "worthington_test"
password = os.getenv("ACTIVEMQ_PASSWORD") or "level3"
host = os.getenv("ACTIVEMQ_HOST") or "localhost"
port = os.getenv("ACTIVEMQ_PORT") or 61613
# destination = sys.argv[1:2] or ["/topic/event"]
# destination = destination[0]
dest = "from_entec_test"
#For Production
# dest = "from_entec"
try:
conn = stomp.Connection10(host_and_ports = [(host, port)])
# conn.start()
# subscribe_id = '-'.join(map(str, (platform.node(), os.getppid(), os.getpid())))
subscribe_id = "Queue Test Listener"
conn.connect(login=user,passcode=password)
message = "This is a test message."
conn.send(dest, message, persistent='true')
print "Sent message containing: " + message
conn.disconnect()
except Exception, error:
reason = str(error)
print "Exception when writing data to queue: " + str(error)
pass
if __name__ == "__main__" :
try:
UploadData = UploadData()
UploadData.ConnectToQueue()
except Exception, Value:
reason = str(Value)
print "Main routine exception: " + str(Value)
pass
I'm not very familiar with Python STOMP clients but from the code you appear to be subscribing using the 'client-individual' mode of STOMP which means that each message you receive requires you to send an ACK frame back with the message Id value so that the remote can mark it as consumed. Since you are not doing that the messages will not be removed from the Queue.
As an alternative you can use the 'auto' acknowledgement mode which marks the message as consumed as soon as the broker dispatches them. To understand the STOMP subscription model please refer to the STOMP specification.

How to convert raw emails (MIME) from AWS SES to Gmail?

I have a gmail account linked to my domain account.
AWS SES will send messages to my S3 bucket. From there, SNS will forward the message in a raw format to my gmail address.
How do I automatically convert the raw message into a standard email format?
The raw message is in the standard email format. I think what you want to know is how to parse that standard raw email into an object that you can manipulate so that you can forward it to yourself and have it look like a standard email. AWS provides a tutorial on how to forward emails with a lambda function, through SES, by first storing them in your S3 bucket: https://aws.amazon.com/blogs/messaging-and-targeting/forward-incoming-email-to-an-external-destination/
If you follow those instructions, you'll find that the email you recieve comes as an attachment, not looking like a standard email. The following code is an alteration of the Python code provided by AWS that does what you're looking for (substitute this for the code provided in the tutorial):
# Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Altered from original by Adam Winter
#
# This file is licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
# OF ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import os
import boto3
import email
import re
import html
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
region = os.environ['Region']
def get_message_from_s3(message_id):
incoming_email_bucket = os.environ['MailS3Bucket']
incoming_email_prefix = os.environ['MailS3Prefix']
if incoming_email_prefix:
object_path = (incoming_email_prefix + "/" + message_id)
else:
object_path = message_id
object_http_path = (f"http://s3.console.aws.amazon.com/s3/object/{incoming_email_bucket}/{object_path}?region={region}")
# Create a new S3 client.
client_s3 = boto3.client("s3")
# Get the email object from the S3 bucket.
object_s3 = client_s3.get_object(Bucket=incoming_email_bucket,
Key=object_path)
# Read the content of the message.
file = object_s3['Body'].read()
file_dict = {
"file": file,
"path": object_http_path
}
return file_dict
def create_message(file_dict):
stringMsg = file_dict['file'].decode('utf-8')
# Create a MIME container.
msg = MIMEMultipart('alternative')
sender = os.environ['MailSender']
recipient = os.environ['MailRecipient']
# Parse the email body.
mailobject = email.message_from_string(file_dict['file'].decode('utf-8'))
#print(mailobject.as_string())
# Get original sender for reply-to
from_original = mailobject['Return-Path']
from_original = from_original.replace('<', '');
from_original = from_original.replace('>', '');
print(from_original)
# Create a new subject line.
subject = mailobject['Subject']
print(subject)
if mailobject.is_multipart():
index = stringMsg.find('Content-Type: multipart/')
stringBody = stringMsg[index:]
#print(stringBody)
stringData = 'Subject: ' + subject + '\nTo: ' + sender + '\nreply-to: ' + from_original + '\n' + stringBody
message = {
"Source": sender,
"Destinations": recipient,
"Data": stringData
}
return message
for part in mailobject.walk():
ctype = part.get_content_type()
cdispo = str(part.get('Content-Disposition'))
# case for each common content type
if ctype == 'text/plain' and 'attachment' not in cdispo:
bodyPart = MIMEText(part.get_payload(decode=True), 'plain', part.get_content_charset())
msg.attach(bodyPart)
if ctype == 'text/html' and 'attachment' not in cdispo:
mt = MIMEText(part.get_payload(decode=True), 'html', part.get_content_charset())
email.encoders.encode_quopri(mt)
del mt['Content-Transfer-Encoding']
mt.add_header('Content-Transfer-Encoding', 'quoted-printable')
msg.attach(mt)
if 'attachment' in cdispo and 'image' in ctype:
mi = MIMEImage(part.get_payload(decode=True), ctype.replace('image/', ''))
del mi['Content-Type']
del mi['Content-Disposition']
mi.add_header('Content-Type', ctype)
mi.add_header('Content-Disposition', cdispo)
msg.attach(mi)
if 'attachment' in cdispo and 'application' in ctype:
ma = MIMEApplication(part.get_payload(decode=True), ctype.replace('application/', ''))
del ma['Content-Type']
del ma['Content-Disposition']
ma.add_header('Content-Type', ctype)
ma.add_header('Content-Disposition', cdispo)
msg.attach(ma)
# not multipart - i.e. plain text, no attachments, keeping fingers crossed
else:
body = MIMEText(mailobject.get_payload(decode=True), 'UTF-8')
msg.attach(body)
# The file name to use for the attached message. Uses regex to remove all
# non-alphanumeric characters, and appends a file extension.
filename = re.sub('[^0-9a-zA-Z]+', '_', subject_original)
# Add subject, from and to lines.
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = recipient
msg['reply-to'] = mailobject['Return-Path']
# Create a new MIME object.
att = MIMEApplication(file_dict["file"], filename)
att.add_header("Content-Disposition", 'attachment', filename=filename)
# Attach the file object to the message.
msg.attach(att)
message = {
"Source": sender,
"Destinations": recipient,
"Data": msg.as_string()
}
return message
def send_email(message):
aws_region = os.environ['Region']
# Create a new SES client.
client_ses = boto3.client('ses', region)
# Send the email.
try:
#Provide the contents of the email.
response = client_ses.send_raw_email(
Source=message['Source'],
Destinations=[
message['Destinations']
],
RawMessage={
'Data':message['Data']
}
)
# Display an error if something goes wrong.
except ClientError as e:
print('send email ClientError Exception')
output = e.response['Error']['Message']
else:
output = "Email sent! Message ID: " + response['MessageId']
return output
def lambda_handler(event, context):
# Get the unique ID of the message. This corresponds to the name of the file
# in S3.
message_id = event['Records'][0]['ses']['mail']['messageId']
print(f"Received message ID {message_id}")
# Retrieve the file from the S3 bucket.
file_dict = get_message_from_s3(message_id)
# Create the message.
message = create_message(file_dict)
# Send the email and print the result.
result = send_email(message)
print(result)
For those getting this error:
'bytes' object has no attribute 'encode'
In this line:
body = MIMEText(mailobject.get_payload(decode=True), 'UTF-8')
I could make it work. I am not an expert on this so the code might need some improvement. Also the email body includes html tags. But at least it got delivered.
If decoding the email still fails the error message will appear in your CloudWatch log. Also you will receive an email with the error message.
payload = mailobject.get_payload(decode=True)
try:
decodedPayload = payload.decode()
body = MIMEText(decodedPayload, 'UTF-8')
msg.attach(body)
except Exception as error:
errorMsg = "An error occured when decoding the email payload:\n" + str(error)
print(errorMsg)
body = errorMsg + "\nPlease download it manually from the S3 bucket."
msg.attach(MIMEText(body, 'plain'))
It is up to you which information you want to add to the error email like the subject or the from address.
Just another hint: With the above code you will get an error because subject_original is undefinded. Just delete the following lines.
# The file name to use for the attached message. Uses regex to remove all
# non-alphanumeric characters, and appends a file extension.
filename = re.sub('[^0-9a-zA-Z]+', '_', subject_original)
# Create a new MIME object.
att = MIMEApplication(file_dict["file"], filename)
att.add_header("Content-Disposition", 'attachment', filename=filename)
# Attach the file object to the message.
msg.attach(att)
As far as I understand this code is supposed to add the original email as an attachment which was not what I wanted.

trac SmtpLdapEmailSender to field is empty

I am getting the following problem with this plugin. using trac 0.12.5 on centos 5. the following log is from a comment. user responding is sharif.uddin, user created is jason. and user i am trying to cc to is ramy.
Trac[paradox:env] INFO: Reloading environment due to configuration change
Trac[paradox:env] INFO: -------------------------------- environment startup [Trac 0.12.5] --------------------------------
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.01 seconds
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.00 seconds
Trac[paradox:env] INFO: Reloading environment due to configuration change
Trac[paradox:env] INFO: -------------------------------- environment startup [Trac 0.12.5] --------------------------------
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.06 seconds
Trac[paradox:SmtpLdapEmailSender] INFO: Binding to LDAP as cn=Administrator,cn=Users,dc=domain,dc=com
Trac[paradox:SmtpLdapEmailSender] INFO: Updating list of recipients
Trac[paradox:SmtpLdapEmailSender] WARNING: Searching LDAP server ldap://echo.uk.domain.com for user jasona#DOMAIN.COM
Trac[paradox:SmtpLdapEmailSender] WARNING: Found e-mail address: Jason.Aftalion#domain.com
Trac[paradox:SmtpLdapEmailSender] WARNING: Searching LDAP server ldap://echo.uk.domain.com for user sharifu#DOMAIN.COM
Trac[paradox:SmtpLdapEmailSender] WARNING: Found e-mail address: Sharif.Uddin#domain.com
Trac[paradox:SmtpLdapEmailSender] WARNING: Searching LDAP server ldap://echo.uk.domain.com for user Ramy.Mahmoud#domain.com
Trac[paradox:notification] INFO: Sending notification through SMTP at hero.uk.domain.com:25 to ['Jason.Aftalion#domain.com', 'Sharif.Uddin#domain.com', u'Ramy.Mahmoud#domain.com', 'support#domain.com']
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.01 seconds
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.00 seconds
I have the following code for the plugin in site-packages
class SmtpLdapEmailSender(SmtpEmailSender):
implements(IEmailSender)
email_ldap_serveruri = Option('notification', 'email_ldap_serveruri', '',
"""AD LDAP Server to use for looking up e-mail addresses""")
email_ldap_port = IntOption('notification', 'email_ldap_port', 389, """AD LDAP Server port""")
email_ldap_binddn = Option('notification', 'email_ldap_binddn', '',
"""Bind DN for LDAP lookup. If not given, Kerberos auth will be used for current user""")
email_ldap_bindpw = Option('notification', 'email_ldap_bindpw', '', """Password for non-kerberos auth""")
email_ldap_basedn = Option('notification', 'email_ldap_basedn', '', """Base DN to use for LDAP searches""")
email_attr = 'mail'
def __init__(self):
self.log.warn("Initialising LDAP object with URI: ", self.email_ldap_serveruri)
self.ldap_conn=ldap.initialize(self.email_ldap_serveruri)
def send(self, from_addr, recipients, message):
#self.log.warn(recipients)
if self.email_ldap_binddn != None:
self.log.info("Binding to LDAP as " + self.email_ldap_binddn)
self.ldap_conn.bind_s(self.email_ldap_binddn, self.email_ldap_bindpw, ldap.AUTH_SIMPLE)
else:
self.log.info("Binding to LDAP with Kerberos")
self.ldap_conn.bind_s()
#Iterate through recipients, checking for correct e-mail addresses in LDAP
#Output in ldapRecipients
self.log.info("Updating list of recipients")
new_recipients = []
def isset(variable):
return variable in locals() or variable in globals()
for i, addr in enumerate(recipients):
self.log.warn("Searching LDAP server %s for user %s", self.email_ldap_serveruri, addr)
search_string = 'userPrincipalName=' + addr
result = self.ldap_conn.search_s(self.email_ldap_basedn, ldap.SCOPE_SUBTREE, search_string, [self.email_attr])
#result is formatted as a string (result) in a list of [attr values], in a dictionary of {attr_name=>attr_values}
#in a tuple of (DN, Entry), within a list of results. So result for principle name jasona#domain.com would be
#[('CN=Jason Aftalion,OU=TechSupport,OU=Woking,OU=Sites,DC=domain,DC=com', {'mail': ['Jason.Aftalion#domain.com']})]
#self.log.error(addr)
if len(result) > 0:
if result[0][1][self.email_attr][0]:
self.log.warn("Found e-mail address: " + result[0][1][self.email_attr][0])
new_recipients.append(result[0][1][self.email_attr][0])
else:
self.log.warn("Could not find e-mail address")
new_recipients.append(addr)
else:
new_recipients.append(addr)
new_recipients.append("support#domain.com")
#self.log.error(new_recipients)
return super(SmtpLdapEmailSender,self).send(from_addr, new_recipients, message)
Also when the email gets sent out there is no one on the to address. I think i need to add the u before the quites open on the email if you see the log line Trac[paradox:notification] INFO: Sending notification through SMTP at hero.uk.domain.com:25 to ['Jason.Aftalion#domian.com', 'Sharif.Uddin#domian.com', u'Ramy.Mahmoud#domain.com'] . ramy is the only one that appears in the email as it is placed on the cc section of the ini file.
UPDATE
[root#hero plugins]# easy_install http://trac-hacks.org/svn/announcerplugin/trunk
Downloading http://trac-hacks.org/svn/announcerplugin/trunk
Doing subversion checkout from http://trac-hacks.org/svn/announcerplugin/trunk to /tmp/easy_install-hkATrd/trunk
Processing trunk
Running setup.py -q bdist_egg --dist-dir /tmp/easy_install-hkATrd/trunk/egg-dist-tmp-dGEGqu
File "build/bdist.linux-i686/egg/announcer/opt/bitten/announce.py", line 71
yield
^
SyntaxError: invalid syntax
zip_safe flag not set; analyzing archive contents...
TracAnnouncer 1.0dev-r12503 is already the active version in easy-install.pth
Installed /usr/lib/python2.4/site-packages/TracAnnouncer-1.0dev_r12503-py2.4.egg
Processing dependencies for TracAnnouncer==1.0dev-r12503
Finished processing dependencies for TracAnnouncer==1.0dev-r12503
UPDATE 2
It installed successfully
easy_install http://trac-hacks.org/svn/announcerplugin/trunk
Downloading http://trac-hacks.org/svn/announcerplugin/trunk
Doing subversion checkout from http://trac-hacks.org/svn/announcerplugin/trunk to /tmp/easy_install-AGCmXH/trunk
Processing trunk
Running setup.py -q bdist_egg --dist-dir /tmp/easy_install-AGCmXH/trunk/egg-dist-tmp-6tmNSt
zip_safe flag not set; analyzing archive contents...
Removing TracAnnouncer 1.0dev-r12503 from easy-install.pth file
Adding TracAnnouncer 1.0dev-r13963 to easy-install.pth file
Installed /usr/lib/python2.4/site-packages/TracAnnouncer-1.0dev_r13963-py2.4.egg
Processing dependencies for TracAnnouncer==1.0dev-r13963
Finished processing dependencies for TracAnnouncer==1.0dev-r13963
I get following in log file now. I cannot install python 2.7
Trac[paradox:env] INFO: -------------------------------- environment startup [Trac 0.12.5] --------------------------------
Trac[paradox:loader] ERROR: Skipping "announcer.email_decorators = announcer.email_decorators":
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/Trac-0.12.5-py2.4.egg/trac/loader.py", line 68, in _load_eggs
entry.load(require=True)
File "/usr/lib/python2.4/site-packages/setuptools-0.6c11-py2.4.egg/pkg_resources.py", line 1954, in load
entry = __import__(self.module_name, globals(),globals(), ['__name__'])
File "build/bdist.linux-i686/egg/announcer/email_decorators.py", line 7, in ?
ImportError: No module named utils
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.66 seconds
local ini file
cat /data/intranet/html/trac/paradox/conf/trac.ini
# -*- coding: utf-8 -*-
[changeset]
max_diff_files = 0
[components]
acct_mgr.admin.accountmanageradminpanel = disabled
acct_mgr.api.accountmanager = disabled
acct_mgr.db.sessionstore = disabled
acct_mgr.guard.accountguard = disabled
acct_mgr.macros.accountmanagerwikimacros = disabled
acct_mgr.notification.accountchangelistener = disabled
acct_mgr.notification.accountchangenotificationadminpanel = disabled
acct_mgr.register.emailcheck = disabled
acct_mgr.register.emailverificationmodule = disabled
advancedworkflow.controller.ticketworkflowopownercomponent = disabled
advancedworkflow.controller.ticketworkflowopownerfield = disabled
advancedworkflow.controller.ticketworkflowopownerprevious = disabled
advancedworkflow.controller.ticketworkflowopresetmilestone = disabled
advancedworkflow.controller.ticketworkflowoprunexternal = disabled
advancedworkflow.controller.ticketworkflowopstatusprevious = disabled
advancedworkflow.controller.ticketworkflowoptriage = disabled
advancedworkflow.controller.ticketworkflowopxref = disabled
announcer.api.announcementsystem = enabled
announcer.api.subscriptionresolver = enabled
announcer.distributors.mail.emaildistributor = enabled
announcer.distributors.mail.sendmailemailsender = enabled
announcer.distributors.mail.smtpemailsender = enabled
announcer.email_decorators.announceremaildecorator = enabled
announcer.email_decorators.staticemaildecorator = enabled
announcer.email_decorators.threadingemaildecorator = enabled
announcer.email_decorators.ticketaddlheaderemaildecorator = enabled
announcer.email_decorators.ticketsubjectemaildecorator = enabled
announcer.email_decorators.wikisubjectemaildecorator = enabled
announcer.filters.defaultpermissionfilter = enabled
announcer.formatters.ticketformatter = enabled
announcer.formatters.wikiformatter = enabled
announcer.opt.subscribers.allticketsubscriber = enabled
announcer.opt.subscribers.generalwikisubscriber = enabled
announcer.opt.subscribers.joinablegroupsubscriber = enabled
announcer.opt.subscribers.ticketcomponentownersubscriber = enabled
announcer.opt.subscribers.ticketcomponentsubscriber = enabled
announcer.opt.subscribers.ticketcustomfieldsubscriber = enabled
announcer.opt.subscribers.userchangesubscriber = enabled
announcer.opt.subscribers.watchsubscriber = enabled
announcer.pref.announcerpreferences = enabled
announcer.pref.subscriptionmanagementpanel = enabled
announcer.producers.attachmentchangeproducer = enabled
announcer.producers.ticketchangeproducer = enabled
announcer.producers.wikichangeproducer = enabled
announcer.resolvers.defaultdomainemailresolver = enabled
announcer.resolvers.sessionemailresolver = enabled
announcer.resolvers.specifiedemailresolver = enabled
announcer.resolvers.specifiedxmppresolver = enabled
announcer.subscribers.carboncopysubscriber = enabled
announcer.subscribers.ticketownersubscriber = enabled
announcer.subscribers.ticketreportersubscriber = enabled
announcer.subscribers.ticketupdatersubscriber = enabled
spectrum.smtpldapemailsender.smtpldapemailsender = enabled
tracopt.mimeview.php.phprenderer = enabled
[header_logo]
alt =
link = http://intranet/trac/paradox/
src = common/trac_banner.png
[inherit]
file = /usr/share/trac/conf/trac.ini
[logging]
log_level = INFO
log_type = file
[project]
descr = Paradox replacement
name = Paradox
url = http://intranet/sidb
[ticket]
default_component = other
default_milestone = create/update project
default_version = v12
[ticket-workflow]
accept = new -> assigned
accept.operations = set_owner_to_self
accept.permissions = TICKET_MODIFY
leave = * -> *
leave.default = 1
leave.operations = leave_status
reassign = new,assigned,reopened -> new
reassign.operations = set_owner
reassign.permissions = TICKET_MODIFY
reopen = closed -> reopened
reopen.operations = del_resolution
reopen.permissions = TICKET_CREATE
resolve = new,assigned,reopened -> closed
resolve.operations = set_resolution
resolve.permissions = TICKET_MODIFY
[trac]
base_url = http://intranet/trac/paradox/
check_auth_ip = true
metanav = login,logout,settings,help,about
repository_dir = /data/subversion/paradox
[notification]
smtp_always_cc = Ramy.Mahmoud#domain.com
[announcer]
use_public_cc = true
global ini file
cat ../conf/trac.ini
[announcer]
use_public_cc = true
#admit_domains =
#always_notify_component_owner = true
#always_notify_owner = true
#always_notify_reporter = true
#always_notify_updater = true
#default_email_format = text/html
#email_address_resolvers = SpecifiedEmailResolver, SessionEmailResolver
#ignore_domains =
#mime_encoding = base64
#smtp_always_bcc =
#smtp_always_cc =
#smtp_default_domain =
#smtp_enabled = true
#smtp_from = trac-no-reply#domain.com
#smtp_from_name = Trac
#smtp_password =
#smtp_port = 25
#smtp_replyto = no-reply#domain.com
#smtp_server = hero
#smtp_subject_prefix = __default__
#smtp_timeout = 30
#smtp_user =
#t#icket_email_header_fields = owner, reporter, milestone, component, priority, severity.
#ticket_email_subject = Ticket #${ticket.id}: ${ticket['summary']}.
#ticket_subject_template = $prefix $ticket.id: $summary
#use_public_cc = false
#use_short_addr = false
#use_tls = false
#email_enabled = true
[notification]
always_notify_owner = false
always_notify_reporter = true
always_notify_updater = true
#mime_encoding = base64
#smtp_always_cc = sharifu#domain.com
#smtp_default_domain = domain.com
smtp_enabled = true
smtp_from = trac#domain.com
smtp_password =
smtp_port = 25
smtp_replyto = no-reply#domain.com
smtp_server = hero.uk.domain.com
smtp_subject_prefix = __default__
smtp_user =
use_public_cc = false
use_short_addr = false
use_tls = false
#ignore_domains = domain.com
email_sender=SmtpLdapEmailSender
email_ldap_serveruri = ldap://echo.uk.domain.com
email_ldap_port = 389
email_ldap_basedn = ou=Sites,dc=domain,dc=com
email_ldap_binddn = cn=Administrator,cn=Users,dc=domain,dc=com
email_ldap_bindpw = ****
[ldap]
enable = true
global_perms = true
host = echo
basedn = dc=domain,dc=com
user_rdn = ou=sites
group_rdn = cn=users
store_bind = true
bind_user = cn=Administrator,cn=users,dc=domain,dc=com
bind_passwd = ****
[trac]
base_url = http://intranet/trac/
#permission_store = LdapPermissionStore
[logging]
log_format = Trac[$(basename)s:$(module)s] $(levelname)s: $(message)s
log_type = syslog
log_level = WARN
[components]
webadmin.* = enabled
#ldapauth.* = enabled
#ldapplugin.* = enabled
#ldapplugin.api.ldappermissiongroupprovider = enabled
#ldapplugin.api.ldappermissionstore = disabled
ticketdelete.* = enabled
tracopt.ticket.deleter = enabled
tracwysiwyg.* = enabled
advancedworkflow.* = enabled
#tickettemplate.* = enabled
tracopt.ticket.commit_updater.committicketreferencemacro = enabled
tracopt.ticket.commit_updater.committicketupdater = enabled
ticketchangesets.* = enabled
ticketlog.* = enabled
#announcer.* = enabled
#announcer.api.announcementsystem = enabled
#announcer.distributors.mail.emaildistributor = enabled
#announcer.formatters.ticket.ticketformatter = enabled
#announcer.formatters.wiki.wikiformatter = enabled
#announcer.pref.announcerpreferences = enabled
#announcer.producers.attachment.attachmentchangeproducer = enabled
#announcer.producers.ticket.ticketchangeproducer = enabled
#announcer.producers.wiki.wikichangeproducer = enabled
#announcer.resolvers.sessionemail.sessionemailresolver = enabled
#announcer.subscribers.ticket_compat.carboncopysubscriber = enabled
#announcer.subscribers.ticket_compat.legacyticketsubscriber = enabled
#announcer.subscribers.ticket_components.ticketcomponentsubscriber = enabled
#announcer.subscribers.ticket_custom.ticketcustomfieldsubscriber = enabled
#announcer.subscribers.watch_users.userchangesubscriber = enabled
#announcer.subscribers.watchers.watchsubscriber = enabled
#[tickettemplate]
#field_list = summary, description, reporter, owner, priority, cc, milestone, component, version, type
#enable_custom = true
[ticket-changesets]
check_perms = true
collapsed = false
commands.close = close closed closes fix fixed fixes
commands.refs = addresses re references refs see
compact = true
envelope =
hide_when_none = false
notify = true
resolution = fixed
ticket_comments = true
[ticket]
commit_ticket_update_envelope = []
commit_ticket_update_commands.close =
commit_ticket_update_commands.refs = <ALL>
commit_ticket_update_check_perms = true
commit_ticket_update_notify = true
[ticketlog]
; optional: custom your log message pattern
log_pattern = \s*#%s\s+.*
; optional: set log message's max length, default is no limit
log_message_maxlength = 100
When i leave a comment i see the following extra bit in log file
Trac[paradox:api] ERROR: AnnouncementSystem failed.
Traceback (most recent call last):
File "build/bdist.linux-i686/egg/announcer/api.py", line 560, in _real_send
File "build/bdist.linux-i686/egg/announcer/api.py", line 311, in subscriptions
TypeError: itemgetter expected 1 arguments, got 4
QUESTION 2
Do emails notification not get sent out when adding attachments? i found the following in the log...
Trac[paradox:api] INFO: Synchronized '(default)' repository in 0.01 seconds
Trac[paradox:attachment] INFO: New attachment: ticket:48: RE Conversation with Ringo Au.msg by sharifu#DOMAIN.COM
Trac[paradox:api] ERROR: AnnouncementSystem failed.
Traceback (most recent call last):
File "build/bdist.linux-i686/egg/announcer/api.py", line 560, in _real_send
File "build/bdist.linux-i686/egg/announcer/api.py", line 311, in subscriptions
TypeError: itemgetter expected 1 arguments, got 4

Google Reader API Unread Count

Does Google Reader have an API and if so, how can I get the count of the number of unread posts for a specific user knowing their username and password?
This URL will give you a count of unread posts per feed. You can then iterate over the feeds and sum up the counts.
http://www.google.com/reader/api/0/unread-count?all=true
Here is a minimalist example in Python...parsing the xml/json and summing the counts is left as an exercise for the reader:
import urllib
import urllib2
username = 'username#gmail.com'
password = '******'
# Authenticate to obtain SID
auth_url = 'https://www.google.com/accounts/ClientLogin'
auth_req_data = urllib.urlencode({'Email': username,
'Passwd': password,
'service': 'reader'})
auth_req = urllib2.Request(auth_url, data=auth_req_data)
auth_resp = urllib2.urlopen(auth_req)
auth_resp_content = auth_resp.read()
auth_resp_dict = dict(x.split('=') for x in auth_resp_content.split('\n') if x)
auth_token = auth_resp_dict["Auth"]
# Create a cookie in the header using the SID
header = {}
header['Authorization'] = 'GoogleLogin auth=%s' % auth_token
reader_base_url = 'http://www.google.com/reader/api/0/unread-count?%s'
reader_req_data = urllib.urlencode({'all': 'true',
'output': 'xml'})
reader_url = reader_base_url % (reader_req_data)
reader_req = urllib2.Request(reader_url, None, header)
reader_resp = urllib2.urlopen(reader_req)
reader_resp_content = reader_resp.read()
print reader_resp_content
And some additional links on the topic:
http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI
How do you access an authenticated Google App Engine service from a (non-web) python client?
http://blog.gpowered.net/2007/08/google-reader-api-functions.html
It is there. Still in Beta though.
Here is an update to this answer
import urllib
import urllib2
username = 'username#gmail.com'
password = '******'
# Authenticate to obtain Auth
auth_url = 'https://www.google.com/accounts/ClientLogin'
#auth_req_data = urllib.urlencode({'Email': username,
# 'Passwd': password})
auth_req_data = urllib.urlencode({'Email': username,
'Passwd': password,
'service': 'reader'})
auth_req = urllib2.Request(auth_url, data=auth_req_data)
auth_resp = urllib2.urlopen(auth_req)
auth_resp_content = auth_resp.read()
auth_resp_dict = dict(x.split('=') for x in auth_resp_content.split('\n') if x)
# SID = auth_resp_dict["SID"]
AUTH = auth_resp_dict["Auth"]
# Create a cookie in the header using the Auth
header = {}
#header['Cookie'] = 'Name=SID;SID=%s;Domain=.google.com;Path=/;Expires=160000000000' % SID
header['Authorization'] = 'GoogleLogin auth=%s' % AUTH
reader_base_url = 'http://www.google.com/reader/api/0/unread-count?%s'
reader_req_data = urllib.urlencode({'all': 'true',
'output': 'xml'})
reader_url = reader_base_url % (reader_req_data)
reader_req = urllib2.Request(reader_url, None, header)
reader_resp = urllib2.urlopen(reader_req)
reader_resp_content = reader_resp.read()
print reader_resp_content
Google Reader removed SID auth around June, 2010 (I think), using new Auth from ClientLogin is the new way and it's a bit simpler (header is shorter). You will have to add service in data for requesting Auth, I noticed no Auth returned if you don't send the service=reader.
You can read more about the change of authentication method in this thread.
In the API posted in [1], the "token" field should be "T"
[1] http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI