Appengine error object has no attribute '_key' - google-app-engine

I have a GAE database entity that looks like this:
class Notification(db.Model):
alert = db.StringProperty()
type = db.StringProperty()
status = db.StringProperty(default="unread", choices=set(["unread", "read"]))
created = db.DateTimeProperty(auto_now_add=True)
modified = db.DateTimeProperty(auto_now=True)
entity = db.StringProperty()
record = db.ReferenceProperty(model.RecordModel)
actor = db.ReferenceProperty(model.Profile)
account = db.ReferenceProperty(model.Account)
... and I create an entity like so:
notify = model2.Notification(account=account)
notify.alert = message
notify.type = "reminder"
notify.actor = actor
notify.record = record
notify.put()
This call raises an error *'Notification' object has no attribute '_key'*
nquery = db.Query(model2.Notification).filter('account =', self.session.account).order('-created')
for n in nquery:
try:
_dict = {}
_dict['serverID'] = str(n.key()) #- raises error!

try:
nquery = Notification.all().filter('account =', self.session.account).order('-created')

I think I've figured it out! The "entity" property in my Notification class is causing some sort of naming conflict in python appengine. Changing the name removes the "error object has no attribute '_key'" error. Go figure!

Related

Set a standard object to a custom object's field in salesforce

I want to set a standard object to a custom object's field.
Account a = new Account();
Customer__c sss = new Customer__c();
sss.Ref_Account__c --> this is a field that takes an 'Account' object.
sss.Ref_Account__c = a; This gives me error.
Account a = new Account();
Customer__c sss = new Customer__c();
//sss.Ref_Account__c --> this is a field that takes an 'Account' object.
sss.Ref_Account__c = a.Id;
You need to code like this
sss.Ref_Account__c = a.Ref_Account__c;

How do I write a test class for Messaging.SingleEmailMessage apex class?

I have written the below Apex class that processes incoming email that are sent to an email service address and creates a new task from the incoming mail and then associates this new task with a matching record in salesforce. The match is done on the record name and incoming email subject. The class also sends an email notifying the "Assigned to" user that they have received a reply on a request they are working on.
This works perfect in Sandbox but I have no experience writing test classes. Can anyone advise how I write the test class for the below?
global class RequestEmailHandler implements Messaging.InboundEmailHandler {
global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
String myPlainText = email.plainTextBody;
String subject = email.fromName + ' - ' + email.subject;
system.debug(email);
subject = subject.left(255);
Request__c request;
if (subject != null && subject.trim().length() > 0 && subject.indexOf('(R-') > 0) {
Integer idx = subject.indexOf('(R-');
String requestName = subject.substring(idx+1, subject.indexOf(')', idx));
request = [SELECT Id, Assigned_To__c FROM Request__c WHERE Name = :requestName];
}
if (request == null) {
result.message = 'We were unable to locate the associated request.This may be due to the unique "R" number being removed from the subject line.\n Please include the original email subject when replying to any emails.';
result.success = false;
return result;
}
// Add the email plain text into the local variable
Task task = new Task(
WhatId = request.Id,
Description = myPlainText,
Priority = 'Normal',
Status = 'Completed',
Type = 'Email',
Subject = subject,
ActivityDate = System.today(),
RecordTypeId = '01250000000HkEw');
insert task;
//Find the template
EmailTemplate theTemplate = [select id, name from EmailTemplate where DeveloperName = 'New_Email_Reply2'];
//Create a new email right after the task
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
//Add email To addresses to list
List<String> toAddresses = new List<String>();
toAddresses.add(email.fromAddress);
//Set the list of to addresses
mail.setToAddresses(toAddresses);
//Set the template id
mail.setTemplateId(theTemplate.id);
//The Id of the user
mail.setTargetObjectId(request.Assigned_To__c);
//Set the id of the request
mail.setWhatId(request.Id);
//If you need the email also saved as an activity, otherwise set to false
mail.setSaveAsActivity(false);
//Send Email
try {
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
}
catch (EmailException e) {
system.debug('sendEmail error: ' + e.getMessage());
}
// Save attachments, if any
if (email.textAttachments != null)
{
for(Messaging.Inboundemail.TextAttachment tAttachment : email.textAttachments)
{
Attachment attachment = new Attachment();
attachment.Name = tAttachment.fileName;
attachment.Body = Blob.valueOf(tAttachment.body);
attachment.ParentId = request.Id;
insert attachment;
}
}
//Save any Binary Attachment
if (email.binaryAttachments != null)
{
for(Messaging.Inboundemail.BinaryAttachment bAttachment : email.binaryAttachments) {
Attachment attachment = new Attachment();
attachment.Name = bAttachment.fileName;
attachment.Body = bAttachment.body;
attachment.ParentId = request.Id;
insert attachment;
return result;
}
}
return result;
}
}
Below is my attempt which is only getting 24% coverage. I know it is missing vital code but I do not know enough about test classes to take it any further.
Can anyone assist?
Test Class
#isTest
public class testforemail {
static testMethod void insertRequest() {
Request__c requestToCreate = new Request__c();
requestToCreate.Subject__c= 'test';
requestToCreate.Requested_By_Email__c= 'graham.milne#fmr.com';
insert requestToCreate;
Messaging.InboundEmail email = new Messaging.InboundEmail();
Messaging.InboundEnvelope envelope = new Messaging.InboundEnvelope();
Request__c testRequest = [select Id,Name from Request__c limit 1];
System.debug(testRequest.Name);
email.subject = (testRequest.Name);
email.fromName = 'test test';
email.plainTextBody = 'Hello, this a test email body. for testing purposes only.Phone:123456 Bye';
Messaging.InboundEmail.BinaryAttachment[] binaryAttachments = new Messaging.InboundEmail.BinaryAttachment[1];
Messaging.InboundEmail.BinaryAttachment binaryAttachment = new Messaging.InboundEmail.BinaryAttachment();
binaryAttachment.Filename = 'test.txt';
String algorithmName = 'HMacSHA1';
Blob b = Crypto.generateMac(algorithmName, Blob.valueOf('test'),
Blob.valueOf('test_key'));
binaryAttachment.Body = b;
binaryAttachments[0] = binaryAttachment ;
email.binaryAttachments = binaryAttachments ;
envelope.fromAddress = 'user#fmr.com';
// Add the email plain text into the local variable
Task task = new Task(
WhatId = (testRequest.Id),
Description = email.plainTextBody,
Priority = 'Normal',
Status = 'Completed',
Type = 'Email',
Subject = (testRequest.Name),
ActivityDate = System.today(),
RecordTypeId = '01250000000HkEw');
insert task;
// setup controller object
RequestEmailHandler catcher = new RequestEmailHandler();
Messaging.InboundEmailResult result = catcher.handleInboundEmail(email, envelope);
System.assertEquals( true,result.success );
}
}
The first step is to identify what lines of code are not being covered by your test class.
If you're using Eclipse, you can see this from the Apex Test Runner View.
Or, you can see this from the Developer console as well.
Another thing you need to consider is the isolation of your DML operations in a separate utility class.
public class TestUtils
{
// create request objects method here
// create task objects method here
}
Also, check your debug logs and make sure your code is not throwing any exceptions (i.e., null pointer exceptions, DML exceptions, etc.)
You must also add assertions to check that your code is behaving as expected.
Hope this helps.
The main thing you need to do is to test as many use cases as you can via unit tests.
So, setup data for specific case and run you email processing. After email, check the result using System.assertEquals(). Make separate tests for each use case.
Then, if you don't hit at least 75%, check what is not covered. You, probably, either don't need that code (in case you covered all use cases), or don't write a test for use case, which uses those lines of code.

Why is my write quota reached with a simple admin bulk remove?

This weird case happened twice already in the last 2 days.
I used Datastore Admin to remove all entities, no more than 100, to later reā€“upload db using remote_api_shell but after the request the Datastore Write Operations reached the limit:
This is the first and the only operation I did since last 24h reset.
Also the error is reported in remote_api_shell when I try to put new entities.
Any advice welcome.
Edit:
Here the models, nothing huge...
class Brand(BaseModel):
'''
Brand class
`Marca` in Etax db
'''
name = db.StringProperty()
abbr = db.StringProperty()
def __repr__(self):
return ('<Brand {0} instance at {1}>'
.format(self.abbr.encode('utf-8'), hex(id(self))))
class Model(BaseModel):
'''
Model class
`Gamma` in Etax db
'''
name = db.StringProperty()
code = db.IntegerProperty()
brand = db.ReferenceProperty(Brand, collection_name='models')
def __repr__(self):
return ('<Model {0} instance at {1}>'
.format(self.code, hex(id(self))))
class TrimLevel(BaseModel):
'''
Trim Level class
`Modello` in Etax db
'''
name = db.StringProperty()
etax_code = db.IntegerProperty()
start_production_date = db.DateProperty()
end_production_date = db.DateProperty()
retail_buy_prices = db.ListProperty(int)
retail_sell_prices = db.ListProperty(int)
list_prices = db.ListProperty(int)
model = db.ReferenceProperty(Model, collection_name='trim_levels')
fuel_supply = db.StringProperty()
gear_shift = db.StringProperty()
gear_speeds = db.IntegerProperty()
doors = db.IntegerProperty()
seats = db.IntegerProperty()
kw = db.IntegerProperty()
def __repr__(self):
return ('<TrimLevel {0} instance at {1}>'
.format(self.etax_code, hex(id(self))))
If you look at billing docs, that a high-level delete takes several low-level write operations:
Entity Delete (per entity): 2 writes + 2 writes per indexed property value + 1 write per composite index value
So if 100 entity deletes used 50k write ops, it means that your every entity had 500 index entries.
This can happen when entity has large list properties or havs a compound index spanning multiple list properties (= exploding index)
Do you have any compound indexes defined? What properties does your entity have?

ndb query a model based upon KeyProperty instance

I have a simple ndb model as follows:
class TaskList(ndb.Model):
title = ndb.StringProperty()
description = ndb.TextProperty()
priority = ndb.IntegerProperty()
class UserProfile(ndb.Model):
user = ndb.UserProperty()
tasks = ndb.KeyProperty(TaskList)
As known, a TaskList object will have an Entity Kind Entity Key and an ID.
Given an ID say 7.
I can very well get the object with ID 7 as follows:
task = ndb.Key(TaskList, 7).get()
But how do i get a user who has the task ID 7?
I tried:
tsk = ndb.Key(TaskList, 7).get()
user = UserProfile.query(UserProfile.tasks == tsk.key)
It works, but is there a better method?
You're nearly there - but there's no need to fetch the task, just to use its key property again:
task_key = ndb.Key(TaskList, 7)
user = UserProfile.query(UserProfile.tasks == task_key)
or equivalently:
user = UserProfile.query(UserProfile.tasks == ndb.Key(TaskList, 7))

google datastore many to one references

So i have two model classes:
class Dog(db.model):
dogName = StringProperty()
dogBreed = StringProperty()
class Cat(db.model):
catName = StringProperty()
catBreed = StringProperty()
and then i have a third model class to hold all the pictures
class Images(db.model):
imageReference = ReferenceProperty(*Animal*, collection_name = 'allImages')
imageURL = StringProperty()
Animal is either a Dog or a Cat. Obviously this does not compile.
Now my question is: Is there a way I can put Cat pictures in with Dog pictures? Or do I need to create more models like this:
class DogImages(db.model):
imageReference = ReferenceProperty(Dog, collection_name = 'allImages')
imageURL = StringProperty()
class CatImages(db.model):
imageReference = ReferenceProperty(Cat, collection_name = 'allImages')
imageURL = StringProperty()
You could use PolyModel:
class Animal(polymodel.PolyModel):
name = db.StringProperty()
breed = db.StringProperty()
class Dog(Animal):
pass
class Cat(Animal):
pass
Now you can have a ReferenceProperty that references Animals, and either Dogs or Cats will be permitted.
However, you don't have any properties that are specific to each type of animal - why not just have a regular Animal model, add a property indicating what species it is, and skip the separate models entirely?

Resources