Add owner field to experiment fixes #327

This commit is contained in:
Jared Kerim 2018-05-08 16:07:24 -04:00 коммит произвёл Jared Kerim
Родитель 3bd9383ece
Коммит b9c5464b62
11 изменённых файлов: 118 добавлений и 73 удалений

Просмотреть файл

@ -100,6 +100,14 @@ class ExperimentConstants(object):
'Does this study affect a large number of Release users?')
# Help texts
OWNER_HELP_TEXT = """
<p>
The owner of the experiment is the person responsible for ensuring
that it is run in its entirety and is the primary stake holder in
its analysis.
</p>
"""
PROJECT_HELP_TEXT = format_lazy("""
<p>
Choose which project this experiment belongs to.

Просмотреть файл

@ -1,6 +1,7 @@
import json
from django import forms
from django.contrib.auth import get_user_model
from django.utils.text import slugify
from experimenter.projects.forms import AutoNameSlugFormMixin
@ -36,6 +37,7 @@ class NameSlugMixin(object):
class ControlVariantForm(NameSlugMixin, forms.ModelForm):
description = forms.CharField(
label='Description',
help_text=Experiment.CONTROL_DESCRIPTION_HELP_TEXT,
@ -84,6 +86,7 @@ class ControlVariantForm(NameSlugMixin, forms.ModelForm):
class ExperimentalVariantForm(NameSlugMixin, forms.ModelForm):
slug = forms.CharField(required=False)
experiment = forms.ModelChoiceField(
required=False, queryset=Experiment.objects.all())
@ -152,6 +155,14 @@ class ChangeLogMixin(object):
class ExperimentOverviewForm(
AutoNameSlugFormMixin, ChangeLogMixin, forms.ModelForm):
owner = forms.ModelChoiceField(
required=False,
label='Owner',
help_text=Experiment.OWNER_HELP_TEXT,
queryset=get_user_model().objects.all(),
widget=forms.Select(attrs={'class': 'form-control'}),
)
project = forms.ModelChoiceField(
required=False,
label='Project',
@ -206,6 +217,7 @@ class ExperimentOverviewForm(
class Meta:
model = Experiment
fields = [
'owner',
'project',
'name',
'slug',

Просмотреть файл

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-08 19:15
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('experiments', '0008_auto_20180503_1747'),
]
operations = [
migrations.AddField(
model_name='experiment',
name='owner',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

Просмотреть файл

@ -22,6 +22,7 @@ class ExperimentManager(models.Manager):
class Experiment(ExperimentConstants, models.Model):
owner = models.ForeignKey(get_user_model(), blank=True, null=True)
project = models.ForeignKey(
'projects.Project',
blank=True,

Просмотреть файл

@ -16,6 +16,7 @@ faker = FakerFactory.create()
class ExperimentFactory(factory.django.DjangoModelFactory):
owner = factory.SubFactory(UserFactory)
project = factory.SubFactory(ProjectFactory)
name = factory.LazyAttribute(lambda o: faker.catch_phrase())
slug = factory.LazyAttribute(lambda o: slugify(o.name))

Просмотреть файл

@ -198,6 +198,7 @@ class TestExperimentOverviewForm(MockRequestMixin, TestCase):
self.project = ProjectFactory.create()
self.data = {
'owner': self.user.id,
'project': self.project.id,
'name': 'A new experiment!',
'short_description': 'Let us learn new things',
@ -215,6 +216,7 @@ class TestExperimentOverviewForm(MockRequestMixin, TestCase):
self.assertTrue(form.is_valid())
experiment = form.save()
self.assertEqual(experiment.owner, self.user)
self.assertEqual(experiment.project, self.project)
self.assertEqual(experiment.status, experiment.STATUS_DRAFT)
self.assertEqual(experiment.name, self.data['name'])

Просмотреть файл

@ -110,6 +110,8 @@ class ExperimentCreateView(ExperimentFormMixin, CreateView):
if 'project' in self.request.GET:
initial['project'] = self.request.GET['project']
initial['owner'] = self.request.user.id
return initial

Просмотреть файл

@ -62,7 +62,7 @@
<footer>
<div class="container">
<div class="row">
<div class="col-md-12 text-center">
<div class="col-md-12 md-mb-20 text-center">
<hr/>
© Mozilla Corporation 2018
</div>

Просмотреть файл

@ -9,7 +9,7 @@
<div class="col-md-9">
<a class="noanchorstyle spaced-text" href="{% url "experiments-detail" slug=experiment.slug %}">
{{ object.name }}
{{ experiment.name }}
</a>
<span class="badge status-color-{{ experiment.status }}">{{ experiment.status }}</span>
</div>
@ -29,30 +29,31 @@
{% if experiment.is_draft %}
<div class="col-md-4 text-right">
<a class="noanchorstyle" href="{% url "experiments-overview-update" slug=object.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
<a class="noanchorstyle" href="{% url "experiments-overview-update" slug=experiment.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
</div>
{% endif %}
</div>
<div class="row card md-pt-15 md-pb-10">
{% if object.is_launched %}
<iframe style="display:block" scrolling="no" frameBorder="0" width="100%" height="450px" src="{{ object.enrollment_dashboard_url }}" ></iframe>
{% if experiment.is_launched %}
<iframe style="display:block" scrolling="no" frameBorder="0" width="100%" height="450px" src="{{ experiment.enrollment_dashboard_url }}" ></iframe>
{% else %}
<div class="col-md-6">
<p><strong>{{ object.proposed_start_date }} - {{ object.proposed_end_date }}</strong></p>
<div class="col-md-8">
<p><strong>Owner: {{ experiment.owner }}</strong></p>
</div>
<div class="col-md-6 text-right">
<h4 class="md-mt-0">{{ object.population }}</h4>
<div class="col-md-4 text-right">
<h4 class="md-mt-0">{{ experiment.population }}</h4>
<p><strong>{{ experiment.proposed_start_date }} - {{ experiment.proposed_end_date }}</strong></p>
</div>
<div class="col-md-12 md-mt-10">
{{ object.short_description|linebreaks }}
<div class="col-md-12">
{{ experiment.short_description|linebreaks }}
</div>
{% endif %}
</div>
<div class="row md-mt-20">
<h4 class="col-md-8">
{% if not object.completed_variants %}
{% if not experiment.completed_variants %}
<span class="icon-warning glyphicon glyphicon-exclamation-sign"></span>
{% endif %}
Firefox Pref &amp; Branches
@ -60,31 +61,31 @@
{% if experiment.is_draft %}
<div class="col-md-4 text-right">
<a class="noanchorstyle" href="{% url "experiments-variants-update" slug=object.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
<a class="noanchorstyle" href="{% url "experiments-variants-update" slug=experiment.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
</div>
{% endif %}
</div>
<div class="row card md-pt-15 md-pb-10">
{% if object.variants.all %}
{% for variant in object.variants.all %}
{% if experiment.variants.all %}
{% for variant in experiment.variants.all %}
<div class="col-md-12 {% if not forloop.last %}md-mb-15{% endif %}">
<h4 class="md-mt-0">{{ variant.ratio }}% {{ variant.name }}</h4>
<p><strong>{{ object.pref_key }} = <span class="text-info">{{ variant.value }}</span></strong></p>
<p><strong>{{ experiment.pref_key }} = <span class="text-info">{{ variant.value }}</span></strong></p>
<p>{{ variant.description }}</p>
</div>
{% endfor %}
{% else %}
<p class="col-md-12">You must <a href="{% url "experiments-variants-update" slug=object.slug %}">define your branches</a> before you can launch your experiment.</p>
<p class="col-md-12">You must <a href="{% url "experiments-variants-update" slug=experiment.slug %}">define your branches</a> before you can launch your experiment.</p>
{% endif %}
</div>
<div class="row md-mt-20">
<h4 class="col-md-8">
{% if not object.completed_objectives %}
{% if not experiment.completed_objectives %}
<span class="icon-warning glyphicon glyphicon-exclamation-sign"></span>
{% endif %}
Objectives
@ -92,24 +93,24 @@
{% if experiment.is_draft %}
<div class="col-md-4 text-right">
<a class="noanchorstyle" href="{% url "experiments-objectives-update" slug=object.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
<a class="noanchorstyle" href="{% url "experiments-objectives-update" slug=experiment.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
</div>
{% endif %}
</div>
<div class="row card md-pt-15 md-pb-10">
<div class="col-md-12">
{% if object.completed_objectives %}
{{ object.objectives|linebreaks }}
{% if experiment.completed_objectives %}
{{ experiment.objectives|linebreaks }}
{% else %}
<p>You must <a href="{% url "experiments-objectives-update" slug=object.slug %}">define the objectives</a> before you can launch your experiment.</p>
<p>You must <a href="{% url "experiments-objectives-update" slug=experiment.slug %}">define the objectives</a> before you can launch your experiment.</p>
{% endif %}
</div>
</div>
<div class="row md-mt-20">
<h4 class="col-md-8">
{% if not object.completed_objectives %}
{% if not experiment.completed_objectives %}
<span class="icon-warning glyphicon glyphicon-exclamation-sign"></span>
{% endif %}
Analysis
@ -117,25 +118,25 @@
{% if experiment.is_draft %}
<div class="col-md-4 text-right">
<a class="noanchorstyle" href="{% url "experiments-objectives-update" slug=object.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
<a class="noanchorstyle" href="{% url "experiments-objectives-update" slug=experiment.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
</div>
{% endif %}
</div>
<div class="row card md-pt-15 md-pb-10">
<div class="col-md-12">
{% if object.completed_objectives %}
{{ object.analysis|linebreaks }}
{% if experiment.completed_objectives %}
{{ experiment.analysis|linebreaks }}
{% else %}
<p>You must <a href="{% url "experiments-objectives-update" slug=object.slug %}">define the analysis plan</a> before you can launch your experiment.</p>
<p>You must <a href="{% url "experiments-objectives-update" slug=experiment.slug %}">define the analysis plan</a> before you can launch your experiment.</p>
{% endif %}
</div>
</div>
<div class="row md-mt-20">
<h4 class="col-md-8">
{% if not object.completed_risks %}
{% if not experiment.completed_risks %}
<span class="icon-warning glyphicon glyphicon-exclamation-sign"></span>
{% endif %}
Risk Assessment
@ -143,42 +144,42 @@
{% if experiment.is_draft %}
<div class="col-md-4 text-right">
<a class="noanchorstyle" href="{% url "experiments-risks-update" slug=object.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
<a class="noanchorstyle" href="{% url "experiments-risks-update" slug=experiment.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
</div>
{% endif %}
</div>
<div class="row card md-pt-15 md-pb-10">
<div class="col-md-12">
{% if object.completed_risks %}
<p><strong>{{ object.RISK_PARTNER_RELATED_LABEL }}</strong></p>
<p>{{ object.risk_partner_related|yesno:"Yes,No" }}</p>
{% if experiment.completed_risks %}
<p><strong>{{ experiment.RISK_PARTNER_RELATED_LABEL }}</strong></p>
<p>{{ experiment.risk_partner_related|yesno:"Yes,No" }}</p>
<p><strong>{{ object.RISK_BRAND_LABEL }}</strong></p>
<p>{{ object.risk_brand|yesno:"Yes,No" }}</p>
<p><strong>{{ experiment.RISK_BRAND_LABEL }}</strong></p>
<p>{{ experiment.risk_brand|yesno:"Yes,No" }}</p>
<p><strong>{{ object.RISK_FAST_SHIPPED_LABEL }}</strong></p>
<p>{{ object.risk_fast_shipped|yesno:"Yes,No" }}</p>
<p><strong>{{ experiment.RISK_FAST_SHIPPED_LABEL }}</strong></p>
<p>{{ experiment.risk_fast_shipped|yesno:"Yes,No" }}</p>
<p><strong>{{ object.RISK_CONFIDENTIAL_LABEL }}</strong></p>
<p>{{ object.risk_confidential|yesno:"Yes,No" }}</p>
<p><strong>{{ experiment.RISK_CONFIDENTIAL_LABEL }}</strong></p>
<p>{{ experiment.risk_confidential|yesno:"Yes,No" }}</p>
<p><strong>{{ object.RISK_RELEASE_POPULATION_LABEL }}</strong></p>
<p>{{ object.risk_release_population|yesno:"Yes,No" }}</p>
<p><strong>{{ experiment.RISK_RELEASE_POPULATION_LABEL }}</strong></p>
<p>{{ experiment.risk_release_population|yesno:"Yes,No" }}</p>
{% if object.is_high_risk %}
{% if experiment.is_high_risk %}
<h5>RASCI Owners and Deliverables</h5>
{{ object.risks|linebreaks }}
{{ experiment.risks|linebreaks }}
{% endif %}
{% else %}
<p>You must <a href="{% url "experiments-risks-update" slug=object.slug %}">define the risks</a> before you can launch your experiment.</p>
<p>You must <a href="{% url "experiments-risks-update" slug=experiment.slug %}">define the risks</a> before you can launch your experiment.</p>
{% endif %}
</div>
</div>
<div class="row md-mt-20">
<h4 class="col-md-8">
{% if not object.completed_risks %}
{% if not experiment.completed_risks %}
<span class="icon-warning glyphicon glyphicon-exclamation-sign"></span>
{% endif %}
Testing Plan
@ -186,17 +187,17 @@
{% if experiment.is_draft %}
<div class="col-md-4 text-right">
<a class="noanchorstyle" href="{% url "experiments-risks-update" slug=object.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
<a class="noanchorstyle" href="{% url "experiments-risks-update" slug=experiment.slug %}"><h5><span class="glyphicon glyphicon-pencil"></span> Edit</h5></a>
</div>
{% endif %}
</div>
<div class="row card md-pt-15 md-pb-10">
<div class="col-md-12">
{% if object.completed_risks %}
{{ object.testing|linebreaks }}
{% if experiment.completed_risks %}
{{ experiment.testing|linebreaks }}
{% else %}
<p>You must <a href="{% url "experiments-risks-update" slug=object.slug %}">define the QA plan</a> before you can launch your experiment.</p>
<p>You must <a href="{% url "experiments-risks-update" slug=experiment.slug %}">define the QA plan</a> before you can launch your experiment.</p>
{% endif %}
</div>
</div>
@ -206,7 +207,7 @@
<div class="col-md-3">
{% if experiment.is_draft %}
{% if object.is_ready_for_review %}
{% if experiment.is_ready_for_review %}
<form
action="{% url "experiments-status-update" slug=experiment.slug %}"
method="POST"
@ -253,7 +254,7 @@
{% endif %}
<h5>History</h5>
{% for change in object.changes.all reversed %}
{% for change in experiment.changes.all reversed %}
<div class="row help-block">
<div class="col-md-12">
<p>{{ change.changed_on.date }}</p>

Просмотреть файл

@ -1,7 +1,7 @@
{% extends "experiments/edit_base.html" %}
{% load static %}
{% block edit_title %}
{% if object %}
Edit {{ object.name }}
@ -15,22 +15,24 @@
{% endblock %}
{% block edit_form %}
<form
class="form-horizontal"
method="POST"
<form
class="form-horizontal"
method="POST"
enctype='multipart/form-data'
>
{% csrf_token %}
{% include "experiments/field_inline.html" with field=form.owner %}
{% include "experiments/field_inline.html" with field=form.name %}
{% include "experiments/field_inline.html" with field=form.short_description %}
<div class="form-group">
<div class="{% if form.errors.population_percent %}has-error{% endif %}">
<label class="col-md-3 control-label" for="{{ form.population_percent.id_for_label }}">{{ form.population_percent.label }}</label>
<div class="col-md-2 ">
{{ form.population_percent }}
{{ form.population_percent }}
</div>
</div>
<div class="col-md-1">
@ -45,7 +47,7 @@
{% if form.errors.population_percent %}
<div class="col-md-9 col-md-offset-3 has-error text-right">
{% for error in form.errors.population_percent %}
<label for="{{ form.population_percent.id_for_label }}" class="control-label">{{ error }}</label>
<label for="{{ form.population_percent.id_for_label }}" class="control-label">{{ error }}</label>
{% endfor %}
</div>
{% endif %}
@ -58,9 +60,9 @@
</div>
{% include "experiments/field_inline.html" with field=form.client_matching %}
{% include "experiments/field_inline.html" with field=form.proposed_start_date %}
{% include "experiments/field_inline.html" with field=form.proposed_end_date %}
<div class="form-group">
@ -79,7 +81,7 @@
{% block edit_info %}
<h4><span class="glyphicon glyphicon-info-sign"></span> Getting Started</h4>
<p>
Your experiment will start as a draft.
Your experiment will start as a draft.
</p>
<p>
Fill out the information on this page to save your draft.
@ -89,7 +91,7 @@
now or later.
</p>
<p>
When all of the sections are complete and reviewed, you can
When all of the sections are complete and reviewed, you can
launch your experiment to Shield.
</p>
{% endblock %}

Просмотреть файл

@ -44,6 +44,7 @@
<div class="col-md-8">
<h4 class="md-mt-0">
{{ experiment.name }}
<span class="badge status-color-{{ experiment.status }}">{{ experiment.status }}</span>
</h4>
</div>
</div>
@ -52,22 +53,14 @@
<div class="col-md-8">
<h5>
<span class="badge status-color-{{ experiment.status }}">{{ experiment.status }}</span>
by
{{ experiment.changes.latest.changed_by }}
on
{{ experiment.changes.latest.changed_on.date }}
Owner: {{ experiment.owner }}
</h5>
{{ experiment.short_description|linebreaks }}
</div>
<div class="col-md-4 text-right">
<h4>
{{ experiment.population }}
</h4>
</div>
<div class="col-md-12 md-mt-5">
<p>{{ experiment.short_description }}</p>
<h4>{{ experiment.population }}</h4>
<p><strong>{{ experiment.proposed_start_date }} - {{ experiment.proposed_end_date }}</strong></p>
</div>
</div>