+ Start a Discussion
steve_andersensteve_andersen 

Sites public user to edit contacts?

Here's my use case for a sites app:

1. Send an email out to Contacts via sf.com
2. Include a "manage my subscriptions" link in the email that has the contact id in it
3. End user clicks on that URL and lands on a sites page
4. End user is asked to enter the email address for which they want to modify subscriptions.
5. If the email they enter matches the email on the contact record, the can
6. change some settings on their contact record and hit save to commit them

I had this working in the authenticated view, but can't get sites to allow me to modify contact records as a public user. I can see why sf.com might not want to allow that. But I also don't want to make a person authenticate for this task.

So I changed things to allow the user to create a custom object that manages the subscription, and then I have a trigger on that object to update the contact record with the changes. So in effect, they are modifying the contact, but with a custom object and a trigger in between.

However, Sites won't let me do this unauthenticated. The checkboxes on my custom object don't show on the vf page. I don't get "authorization required" but the fields just aren't there.

Is Sites seeing my trigger and disallowing my public user because it knows I am going to update a Contact? Or am I screwing things up in a different way?

Here is the page:
Code:
<apex:page Controller="ext_contact_subscriptions" showHeader="False" title="Manage Your Subscriptions" >
<!-- Begin Default Content REMOVE THIS -->
<div style="margin:10px">
<h1>Manage your Subscriptions</h1>
<p>Check what you want to receive from us!</p>
<apex:form >
 <apex:outputPanel id="emailLogin" layout="block" style="margin-left:10px;"> 
  <apex:outputPanel rendered="{!AND(NOT(emailVerified),NOT(success))}" >
   <apex:outputText value="Your email:"/>
   <apex:inputText value="{!enteredEmail}" />
   <apex:commandButton value="submit" action="{!validateEmail}" rerender="emailLogin,subscriptions"/>
  </apex:outputPanel>
  <apex:outputPanel rendered="{!validationError}" layout="block">
  <br/>
   <apex:outputText style="color:#ff0000;" value="That email did not match this subscription. Try another email address."/>
  </apex:outputPanel>
 </apex:outputPanel>
 <apex:outputPanel id="subscriptions" layout="block" style="margin-left:10px;">
  <apex:outputPanel rendered="{!AND(emailVerified,NOT(success))}">
   <h2>Change your Email if you Wish</h2>
   <br/><br/>
   <apex:outputText value="Your Email: " style="margin-left:10px;"/> <apex:inputField value="{!subscription.Email__c}" /><br/><br/>
   <h2>Your Subscriptions</h2>
   <br/><br/>
   <apex:inputField value="{!subscription.Monthly_eNewsletter__c}" /> <apex:outputText value="eNewsletter"/>
   <br/><br/>
   
   <apex:outputText style="color:#666666;margin-left:10px;" value="Receive our monthly newsletter."/><br/><br/>
   <apex:inputField value="{!subscription.Action_Alerts__c}" /> <apex:outputText value="Action Alerts"/>
   <br/><br/>
   <apex:outputText style="color:#666666;margin-left:10px;" value="Receive our periodic notifications about actions."/><br/><br/>
   <apex:commandButton action="{!save}" value="Save" rerender="emailLogin,subscriptions,success"/>
  </apex:outputPanel>
 </apex:outputPanel>
 <apex:outputPanel id="success" layout="block" style="margin-left:10px;">
  <apex:outputPanel rendered="{!success}">
   <apex:outputText style="color:#666666;margin-left:10px;" value="Thanks for submitting your changes! They will go into effect immediately."/>
  </apex:outputPanel>
 </apex:outputPanel>
 <!--figure out redirect-->

</apex:form>
</div>
</apex:page>


Here is the controller:

Code:
public class ext_contact_subscriptions {
 
 public Contact contact = new Contact();
 
 public Boolean emailVerified   { get; set; }
 public String enteredEmail    { get; set; }
 public Boolean success     { get; set; }
 public Boolean validationError   { get; set; }
 public string msg       { get; set; }
 
 public Subscription__c subscription { get {return subscription;} set {subscription = value;} }
  
 public ext_contact_subscriptions() {
        contact = [select id, email,Monthly_eNewsletter__c, Action_Alerts__c from contact where id = :ApexPages.currentPage().getParameters().get('id')];
        emailVerified = false;
        validationError = false;
        success = false;
        subscription = new Subscription__c();
        subscription.Contact__c = contact.Id;
        subscription.Email__c = contact.Email;
        subscription.Monthly_eNewsletter__c = contact.Monthly_eNewsletter__c;
        subscription.Action_Alerts__c = contact.Action_Alerts__c;
    }
    
    public PageReference validateEmail() {
     //contact.email = 'steve@test.com';
     if (enteredEmail == contact.email) {
      emailVerified = true;
      validationError = false;
     } else {
      validationError = true; 
     }
     return null; 
    }
    
    
    public PageReference save() {
     
     try {
        // update contact;
       // subscription.contact__c = contact.Id;
     //   subscription.email__c = contact.email;
      //  subscription.Monthly_eNewsletter__c = contact.Monthly_eNewsletter__c;
      //  subscription.Action_Alerts__c = contact.Action_Alerts__c;
        insert subscription;
        
         success = true;
        } catch (exception e) { 
         msg = e.getMessage(); 
        }
     
     return null; 
    }
}

 and here is the trigger:

Code:
trigger subscription_to_contact on subscription__c (after insert) {
 Map<Id,subscription__c> subsToKill = new Map<Id,subscription__c>();
 List<Contact> contactsToProcess = new List<Contact>();
 for (subscription__c sub : Trigger.new) {
  Contact contact = new Contact (    
   id=sub.contact__c,
   Email = sub.email__c,
   Action_Alerts__c = sub.Action_Alerts__c,
   Monthly_eNewsletter__c = sub.Monthly_eNewsletter__c
  );
  contactsToProcess.add(contact);
  subsToKill.put(sub.id,sub);
 }
 if(contactsToProcess.size()>0){
  try {
   update contactsToProcess;  
   //delete subsToKill.values();
        } catch (exception e) { 
         system.debug(e.getMessage()); 
        }  
 } 
}

 Thanks much!

Steve


 

Best Answer chosen by Admin (Salesforce Developers) 
BulentBulent
We are planning to fix the issue related to "page not found" in the next release.
With Force.com Sites you can only make visualforce pages public (after portal authentication standard pages are supported based on portal licenses as well).

Standard controller actions would take you to the standard pages and standard pages are not enabled for anonymous access.
You can assign a visualforce page and override the actions of any object from the object details page (Standard buttons and links -> override with a visualforce page). However, this change would apply to all users not just site access.

As you mentioned, you can write a custom controller or extend the standard controller to capture the actions and redirect them to related visualforce pages.

All Answers

jwetzlerjwetzler
If the fields aren't there that's probably FLS doing it's thing.  By default when you create fields they are set to not visible for sites users.  Did you go in and mark them as visible?
steve_andersensteve_andersen
That was it!

I'd still love to be able to edit Contacts with Sites, but now my code works with the custom object making the Contact edit via a trigger.

Thanks!

Steve
BulentBulent
Developer edition site license gives you Read and Create on standard objects (except you only get Read access on Products, Pricebooks and Ideas objects), and full access on custom objects.

The compliant way to do this is to authenticate users to get the edit/delete access
sslatersslater
If we look on the page to edit the public sites profile, there is no option to allow editing or deleting of standard objects. Is there a reason for this and what can we do to enable that? Otherwise, are we forced to use a trigger like the OP or can we somehow extend the standard object so that we can edit it?

This seems like a very common use case and otherwise, we would have to re-create each standard object. Any thoughts on a work-around?
BulentBulent
User license defines the super set of what can be done, you can reduce the access but you can not increase it. Developer edition site license gives you Read and Create on standard objects (except you only get Read access on Products, Pricebooks and Ideas objects), and full access on custom objects.

The compliant way to get additional access is to authenticate users with proper portal licenses.

The way you described would be against the license agreement.
sslatersslater
Thanks Bulent. The sites docs also say it's not allowed.

I'm working with an ISV scoping out the feasibility. If a DE can't edit or delete standard objects, can any other edition? If the plan is to make these different by edition, can you provide a list of how it will be rolled out? What about the $15/month force.com only license?

So if an ISV is writing an app and wants to leverage the standard objects but not have a user account for every visitor (way too expensive), what is the recommended answer?

Thanks!
steve_andersensteve_andersen
Thanks Bulent! Sorry we didn't connect at Dreamforce.

Thanks for clarifying the licensing issues. I hope the license agreement changes to support lightweight data changes without authentication needed.

I've created a short video to show a sample use case: email preferences editing.

The ideas site is currently in maintenance--I'll create a new idea for this licensing change when it comes back up.

Steve
GoForceGoGoForceGo
I am playing around with sites and get unauthorized access message when I try displaying this page with a specific record id.

I
Code:
<apex:page standardController="P1__c">
    <apex:detail/> 
</apex:page>

 
P1 is a custom object. I have set the Public settings to include read/write/create/delete access for this object and exposed all the fields.

P1 share settings are public read/write.

Any ideas what is going on?










Message Edited by GoForceGo on 11-17-2008 09:56 AM
BulentBulent
You might want to check the following:
1- You page is enabled for the site (via the site pages related list on the site details page)
2- If the P1__c object has private sharing then you might want to create a group and add the site guest user to the group and create a sharing rule, or you might want to write a custom controller
3- Field level security is visible for the P1 object fields
4- And you need to pass a record id to the page in order to see the record details

Message Edited by Bulent on 11-17-2008 10:09 AM

Message Edited by Bulent on 11-17-2008 10:20 AM
GoForceGoGoForceGo
Thanks Bulent....

The problem was that i was mistyping the name of the page (forgot a pesky plural form - the 's' in it). Seems like the system was showing unAuthorized page, instead of FilenotFound page, even though my settings were okay.

In the example above, I am able to show the page okay now.

However, I would like the user to be able to "Edit" the page (the Detail page shows only in read mode). When I click the edit button, seems like Sites does not like it.

I guess I am stuck using a custom controller? Ideally, I would just like to use the page layout defined for the custom object and let the user edit it.



BulentBulent
We are planning to fix the issue related to "page not found" in the next release.
With Force.com Sites you can only make visualforce pages public (after portal authentication standard pages are supported based on portal licenses as well).

Standard controller actions would take you to the standard pages and standard pages are not enabled for anonymous access.
You can assign a visualforce page and override the actions of any object from the object details page (Standard buttons and links -> override with a visualforce page). However, this change would apply to all users not just site access.

As you mentioned, you can write a custom controller or extend the standard controller to capture the actions and redirect them to related visualforce pages.
This was selected as the best answer
GoForceGoGoForceGo

Thanks Bulent.

Sounds like I cannot use the predefined page layout....

I have to create a VF page to mimic the page layout and have a custom controller to save the object.

I guess there is no standard VF component to open a standard page layout in Edit mode (the detail tag opens it only in a read mode).








reatlimecoreatlimeco

I have read and edit turned on in the portal user's profile. But when I try to use apex:detail with a standard controller and pass it a subject of $User.contactId, it displays correctly but when I hit the Edit button I get an insufficient privilege.    The problem I think is that the contact record is not owned by the portal user but I can't figure out how to set up sharing to this profile or role.   Anyone know how?

jeniffer homesjeniffer homes
P1 is a custom object. I have set the Public settings to include read/write/create/delete access for this object and exposed all the fields.

Regards,
Jeniffer.
Website:- (http://www.contacttelephonenumbers.com/sky-contact-telephone-number/)
lissa coffeylissa coffey
Thanks, I had this working in the authenticated view, and got  to allow me to modify contact records as a public user.