Integrating 'terms of service' into Anvil apps

Curious how others have implemented a click-through ‘terms of service’ - I’m thinking I’ll simply create a form that displays my ToS with a yes/no button. Yes continues, no logs out. Registering the user’s response in the user table could be a good legal record, and only require acceptance once (unless they change).

In terms of the mechanics of it, yes, that sounds like a perfectly fine approach to me.

2 Likes

You could do a check box with a link.
[ ] I agree to terms of service

This would be nice in the custom_login_flow so you could have it as part of the sign up form and record it in the User’s table upon signing up.

The terms of service link could open up the form with the terms of service inside an alert.

def terms_link_click(self, **event_args):
  from .TOS  import TOS
  alert(TOS, large=True)

I found using a custom HTML form for terms of service was quite nice. Then you can use HTML markup for headings, paragraphs and bullet points.

3 Likes

Excellent suggestion, thanks for the code snippet.

1 Like

I was trying this and had some success testing to see if the user had accepted the T&C then directing to a form that displays the T&Cs with a check box for the user to indicate acceptance . However, the T&C form only flashes on the screen then the user is taken back to the landing page. Theuser never has chance to read nor accept the T&Cs

On the landing Form1 my code is this

  def __init__(self, **properties):
   
    # Set Form properties and Data Bindings.javascript:void(0)
    self.init_components(**properties)

    # Any code you write here will run when the form opens.
    
    anvil.users.login_with_form()
    
    tc = anvil.server.call('check_TandC')
    print(tc)
    if tc == 1:
      open_form('TandCs')

    self.refresh()
    self.repeating_panel_1.set_event_handler('x-refresh', self.refresh)

and on the TandC form it is this

class TandCs(TandCsTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Any code you write here will run when the form opens.
    print('opened T&C')

  def check_box_1_change(self, **event_args):
    """This method is called when this checkbox is checked or unchecked"""
    
    app_tables.users_tandc.client_writable(agree_TandC=True)
    open_form('Form1')
    

  def logout_click(self, **event_args):
    """This method is called when the button is clicked"""
    if anvil.users.get_user():
      anvil.users.logout()
      self.clear()
      anvil.users.login_with_form() 
      
      open_form('Form1')
    pass

the code directly above runs as i can see it print ‘opened T&C’ in the console when check_TandC runs on the server. But the form it self only flashes before returning to the landing form.

What am I missing ?

The server method check_TandC returns 1 if there not a record of the user checking the agree_TandC box in the user table. I want to run the query of the user data table on the server as I feel that is more secure than giving user table access to code running in the client.

Thank you.

it’s because open_form is inside an init method…

Try moving that logic to the form show event…

1 Like

To add to what Stu says, here’s a clone in case it helps (just showing the form_show flow):

I would just like to add that you are correct to keep sensitive operations on the server. The client code is fully exposed to the user. It is fine to return flags to the client that check various things in order to route folks to other forms, but when it comes time to actually return sensitive data, you will still want to consider server-side authentication/permission checking. Security model info here.

1 Like

There is now a cleaner option than running code in form_show! If you want your startup code to decide which form to show, then choose a Startup Module rather than a Startup Form. Your startup module can then have straightforward logic like:

# Start by requiring login
user = anvil.users.login_with_form()

if user['agreed_tos']:
  open_form('HomeForm')
else:
  open_form('TOSForm')

This is a lot neater than loading a form, waiting for it to be shown on the screen, and then navigating to somewhere else!

8 Likes

That’s great. Now to go change all my app login form solutions… :bulb: :running_man:‍♂

2 Likes

Thanks all. will investigate the new cleaner option.

How would I add the option for the user to download a copy of the T&Cs, say in a pdf?

You would probably want to make your desired form(s) into a PDF using Anvil’s PDF features (here is a tutorial). The PDF can be downloaded by your user at the click of a button.

3 Likes

Thanks. That sound like a good idea.