for r in model.reactions:<EOL><INDENT>if r.annotation.get("<STR_LIT>"):<EOL><INDENT>continue<EOL><DEDENT>if len(r.metabolites) != <NUM_LIT:1>:<EOL><INDENT>continue<EOL><DEDENT>met_id = list(r._metabolites)[<NUM_LIT:0>].id<EOL>if r.id.startswith("<STR_LIT>") and r.id == "<STR_LIT>" + met_id:<EOL><INDENT>r.annotation["<STR_LIT>"] = "<STR_LIT>"<EOL><DEDENT>elif r.id.startswith("<STR_LIT>") and r.id == "<STR_LIT>" + met_id:<EOL><INDENT>r.annotation["<STR_LIT>"] = "<STR_LIT>"<EOL><DEDENT><DEDENT>

adds SBO terms for demands and exchanges

    This works for models which follow the standard convention for
    constructing and naming these reactions.

    The reaction should only contain the single metabolite being exchanged,
    and the id should be EX_metid or DM_metid


output_model = cobra_model.copy()<EOL>inactive_metabolites = [m for m in output_model.metabolites<EOL>if len(m.reactions) == <NUM_LIT:0>]<EOL>output_model.remove_metabolites(inactive_metabolites)<EOL>return output_model, inactive_metabolites<EOL>

Remove metabolites that are not involved in any reactions and
    returns pruned model

    Parameters
    ----------
    cobra_model: class:`~cobra.core.Model.Model` object
        the model to remove unused metabolites from

    Returns
    -------
    output_model: class:`~cobra.core.Model.Model` object
        input model with unused metabolites removed
    inactive_metabolites: list of class:`~cobra.core.reaction.Reaction`
        list of metabolites that were removed


output_model = cobra_model.copy()<EOL>reactions_to_prune = [r for r in output_model.reactions<EOL>if len(r.metabolites) == <NUM_LIT:0>]<EOL>output_model.remove_reactions(reactions_to_prune)<EOL>return output_model, reactions_to_prune<EOL>

Remove reactions with no assigned metabolites, returns pruned model

    Parameters
    ----------
    cobra_model: class:`~cobra.core.Model.Model` object
        the model to remove unused reactions from

    Returns
    -------
    output_model: class:`~cobra.core.Model.Model` object
        input model with unused reactions removed
    reactions_to_prune: list of class:`~cobra.core.reaction.Reaction`
        list of reactions that were removed


if cobra_model._trimmed_genes is not None:<EOL><INDENT>for x in cobra_model._trimmed_genes:<EOL><INDENT>x.functional = True<EOL><DEDENT><DEDENT>if cobra_model._trimmed_reactions is not None:<EOL><INDENT>for the_reaction, (lower_bound, upper_bound) incobra_model._trimmed_reactions.items():<EOL><INDENT>the_reaction.lower_bound = lower_bound<EOL>the_reaction.upper_bound = upper_bound<EOL><DEDENT><DEDENT>cobra_model._trimmed_genes = []<EOL>cobra_model._trimmed_reactions = {}<EOL>cobra_model._trimmed = False<EOL>

Undoes the effects of a call to delete_model_genes in place.

    cobra_model:  A cobra.Model which will be modified in place


return {r: parse_gpr(r.gene_reaction_rule)[<NUM_LIT:0>]<EOL>for r in cobra_model.reactions}<EOL>

Generates a dict of compiled gene_reaction_rules

    Any gene_reaction_rule expressions which cannot be compiled or do not
    evaluate after compiling will be excluded. The result can be used in the
    find_gene_knockout_reactions function to speed up evaluation of these
    rules.


potential_reactions = set()<EOL>for gene in gene_list:<EOL><INDENT>if isinstance(gene, string_types):<EOL><INDENT>gene = cobra_model.genes.get_by_id(gene)<EOL><DEDENT>potential_reactions.update(gene._reaction)<EOL><DEDENT>gene_set = {str(i) for i in gene_list}<EOL>if compiled_gene_reaction_rules is None:<EOL><INDENT>compiled_gene_reaction_rules = {r: parse_gpr(r.gene_reaction_rule)[<NUM_LIT:0>]<EOL>for r in potential_reactions}<EOL><DEDENT>return [r for r in potential_reactions<EOL>if not eval_gpr(compiled_gene_reaction_rules[r], gene_set)]<EOL>

identify reactions which will be disabled when the genes are knocked out

    cobra_model: :class:`~cobra.core.Model.Model`

    gene_list: iterable of :class:`~cobra.core.Gene.Gene`

    compiled_gene_reaction_rules: dict of {reaction_id: compiled_string}
        If provided, this gives pre-compiled gene_reaction_rule strings.
        The compiled rule strings can be evaluated much faster. If a rule
        is not provided, the regular expression evaluation will be used.
        Because not all gene_reaction_rule strings can be evaluated, this
        dict must exclude any rules which can not be used with eval.


def delete_model_genes(cobra_model, gene_list,<EOL>cumulative_deletions=True, disable_orphans=False):

if disable_orphans:<EOL><INDENT>raise NotImplementedError("<STR_LIT>")<EOL><DEDENT>if not hasattr(cobra_model, '<STR_LIT>'):<EOL><INDENT>cobra_model._trimmed = False<EOL>cobra_model._trimmed_genes = []<EOL>cobra_model._trimmed_reactions = {}  <EOL><DEDENT>if cobra_model._trimmed_genes is None:<EOL><INDENT>cobra_model._trimmed_genes = []<EOL><DEDENT>if cobra_model._trimmed_reactions is None:<EOL><INDENT>cobra_model._trimmed_reactions = {}<EOL><DEDENT>if not hasattr(gene_list, '<STR_LIT>') orhasattr(gene_list, '<STR_LIT:id>'):  <EOL><INDENT>gene_list = [gene_list]<EOL><DEDENT>if not hasattr(gene_list[<NUM_LIT:0>], '<STR_LIT:id>'):<EOL><INDENT>if gene_list[<NUM_LIT:0>] in cobra_model.genes:<EOL><INDENT>tmp_gene_dict = dict([(x.id, x) for x in cobra_model.genes])<EOL><DEDENT>else:<EOL><INDENT>tmp_gene_dict = dict([(x.name, x) for x in cobra_model.genes])<EOL><DEDENT>gene_list = [tmp_gene_dict[x] for x in gene_list]<EOL><DEDENT>for x in gene_list:<EOL><INDENT>x.functional = False<EOL><DEDENT>if cumulative_deletions:<EOL><INDENT>gene_list.extend(cobra_model._trimmed_genes)<EOL><DEDENT>else:<EOL><INDENT>undelete_model_genes(cobra_model)<EOL><DEDENT>for the_reaction in find_gene_knockout_reactions(cobra_model, gene_list):<EOL><INDENT>if the_reaction in cobra_model._trimmed_reactions:<EOL><INDENT>continue<EOL><DEDENT>old_lower_bound = the_reaction.lower_bound<EOL>old_upper_bound = the_reaction.upper_bound<EOL>cobra_model._trimmed_reactions[the_reaction] = (old_lower_bound,<EOL>old_upper_bound)<EOL>the_reaction.lower_bound = <NUM_LIT:0.><EOL>the_reaction.upper_bound = <NUM_LIT:0.><EOL>cobra_model._trimmed = True<EOL><DEDENT>cobra_model._trimmed_genes = list(set(cobra_model._trimmed_genes +<EOL>gene_list))<EOL>

delete_model_genes will set the upper and lower bounds for reactions
    catalysed by the genes in gene_list if deleting the genes means that
    the reaction cannot proceed according to
    cobra_model.reactions[:].gene_reaction_rule

    cumulative_deletions: False or True.  If True then any previous
    deletions will be maintained in the model.


def remove_genes(cobra_model, gene_list, remove_reactions=True):

gene_set = {cobra_model.genes.get_by_id(str(i)) for i in gene_list}<EOL>gene_id_set = {i.id for i in gene_set}<EOL>remover = _GeneRemover(gene_id_set)<EOL>ast_rules = get_compiled_gene_reaction_rules(cobra_model)<EOL>target_reactions = []<EOL>for reaction, rule in iteritems(ast_rules):<EOL><INDENT>if reaction.gene_reaction_rule is None orlen(reaction.gene_reaction_rule) == <NUM_LIT:0>:<EOL><INDENT>continue<EOL><DEDENT>if remove_reactions and not eval_gpr(rule, gene_id_set):<EOL><INDENT>target_reactions.append(reaction)<EOL><DEDENT>else:<EOL><INDENT>remover.visit(rule)<EOL>new_rule = ast2str(rule)<EOL>if new_rule != reaction.gene_reaction_rule:<EOL><INDENT>reaction.gene_reaction_rule = new_rule<EOL><DEDENT><DEDENT><DEDENT>for gene in gene_set:<EOL><INDENT>cobra_model.genes.remove(gene)<EOL>associated_groups = cobra_model.get_associated_groups(gene)<EOL>for group in associated_groups:<EOL><INDENT>group.remove_members(gene)<EOL><DEDENT><DEDENT>cobra_model.remove_reactions(target_reactions)<EOL>

remove genes entirely from the model

    This will also simplify all gene_reaction_rules with this
    gene inactivated.


def shared_np_array(shape, data=None, integer=False):

size = np.prod(shape)<EOL>if integer:<EOL><INDENT>array = Array(ctypes.c_int64, int(size))<EOL>np_array = np.frombuffer(array.get_obj(), dtype="<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>array = Array(ctypes.c_double, int(size))<EOL>np_array = np.frombuffer(array.get_obj())<EOL><DEDENT>np_array = np_array.reshape(shape)<EOL>if data is not None:<EOL><INDENT>if len(shape) != len(data.shape):<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>same = all(x == y for x, y in zip(shape, data.shape))<EOL>if not same:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>np_array[:] = data<EOL><DEDENT>return np_array<EOL>

Create a new numpy array that resides in shared memory.

    Parameters
    ----------
    shape : tuple of ints
        The shape of the new array.
    data : numpy.array
        Data to copy to the new array. Has to have the same shape.
    integer : boolean
        Whether to use an integer array. Defaults to False which means
        float array.


def step(sampler, x, delta, fraction=None, tries=<NUM_LIT:0>):

prob = sampler.problem<EOL>valid = ((np.abs(delta) > sampler.feasibility_tol) &<EOL>np.logical_not(prob.variable_fixed))<EOL>valphas = ((<NUM_LIT:1.0> - sampler.bounds_tol) * prob.variable_bounds -<EOL>x)[:, valid]<EOL>valphas = (valphas / delta[valid]).flatten()<EOL>if prob.bounds.shape[<NUM_LIT:0>] > <NUM_LIT:0>:<EOL><INDENT>ineqs = prob.inequalities.dot(delta)<EOL>valid = np.abs(ineqs) > sampler.feasibility_tol<EOL>balphas = ((<NUM_LIT:1.0> - sampler.bounds_tol) * prob.bounds -<EOL>prob.inequalities.dot(x))[:, valid]<EOL>balphas = (balphas / ineqs[valid]).flatten()<EOL>alphas = np.hstack([valphas, balphas])<EOL><DEDENT>else:<EOL><INDENT>alphas = valphas<EOL><DEDENT>pos_alphas = alphas[alphas > <NUM_LIT:0.0>]<EOL>neg_alphas = alphas[alphas <= <NUM_LIT:0.0>]<EOL>alpha_range = np.array([neg_alphas.max() if len(neg_alphas) > <NUM_LIT:0> else <NUM_LIT:0>,<EOL>pos_alphas.min() if len(pos_alphas) > <NUM_LIT:0> else <NUM_LIT:0>])<EOL>if fraction:<EOL><INDENT>alpha = alpha_range[<NUM_LIT:0>] + fraction * (alpha_range[<NUM_LIT:1>] - alpha_range[<NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>alpha = np.random.uniform(alpha_range[<NUM_LIT:0>], alpha_range[<NUM_LIT:1>])<EOL><DEDENT>p = x + alpha * delta<EOL>if (np.any(sampler._bounds_dist(p) < -sampler.bounds_tol) or<EOL>np.abs(np.abs(alpha_range).max() * delta).max() <<EOL>sampler.bounds_tol):<EOL><INDENT>if tries > MAX_TRIES:<EOL><INDENT>raise RuntimeError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>LOGGER.info("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>newdir = sampler.warmup[np.random.randint(sampler.n_warmup)]<EOL>sampler.retries += <NUM_LIT:1><EOL>return step(sampler, sampler.center, newdir - sampler.center, None,<EOL>tries + <NUM_LIT:1>)<EOL><DEDENT>return p<EOL>

Sample a new feasible point from the point `x` in direction `delta`.


def __init__(self, model, thinning, nproj=None, seed=None):

<EOL>if model.solver.is_integer:<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>self.model = model.copy()<EOL>self.feasibility_tol = model.tolerance<EOL>self.bounds_tol = model.tolerance<EOL>self.thinning = thinning<EOL>if nproj is None:<EOL><INDENT>self.nproj = int(min(len(self.model.variables)**<NUM_LIT:3>, <NUM_LIT>))<EOL><DEDENT>else:<EOL><INDENT>self.nproj = nproj<EOL><DEDENT>self.n_samples = <NUM_LIT:0><EOL>self.retries = <NUM_LIT:0><EOL>self.problem = self.__build_problem()<EOL>var_idx = {v: idx for idx, v in enumerate(self.model.variables)}<EOL>self.fwd_idx = np.array([var_idx[r.forward_variable]<EOL>for r in self.model.reactions])<EOL>self.rev_idx = np.array([var_idx[r.reverse_variable]<EOL>for r in self.model.reactions])<EOL>self.warmup = None<EOL>if seed is None:<EOL><INDENT>self._seed = int(time())<EOL><DEDENT>else:<EOL><INDENT>self._seed = seed<EOL><DEDENT>self._seed = self._seed % np.iinfo(np.int32).max<EOL>


<EOL>prob = constraint_matrices(self.model, zero_tol=self.feasibility_tol)<EOL>equalities = prob.equalities<EOL>b = prob.b<EOL>bounds = np.atleast_2d(prob.bounds).T<EOL>var_bounds = np.atleast_2d(prob.variable_bounds).T<EOL>homogeneous = all(np.abs(b) < self.feasibility_tol)<EOL>fixed_non_zero = np.abs(prob.variable_bounds[:, <NUM_LIT:1>]) >self.feasibility_tol<EOL>fixed_non_zero &= prob.variable_fixed<EOL>if any(fixed_non_zero):<EOL><INDENT>n_fixed = fixed_non_zero.sum()<EOL>rows = np.zeros((n_fixed, prob.equalities.shape[<NUM_LIT:1>]))<EOL>rows[range(n_fixed), np.where(fixed_non_zero)] = <NUM_LIT:1.0><EOL>equalities = np.vstack([equalities, rows])<EOL>var_b = prob.variable_bounds[:, <NUM_LIT:1>]<EOL>b = np.hstack([b, var_b[fixed_non_zero]])<EOL>homogeneous = False<EOL><DEDENT>nulls = nullspace(equalities)<EOL>return Problem(<EOL>equalities=shared_np_array(equalities.shape, equalities),<EOL>b=shared_np_array(b.shape, b),<EOL>inequalities=shared_np_array(prob.inequalities.shape,<EOL>prob.inequalities),<EOL>bounds=shared_np_array(bounds.shape, bounds),<EOL>variable_fixed=shared_np_array(prob.variable_fixed.shape,<EOL>prob.variable_fixed, integer=True),<EOL>variable_bounds=shared_np_array(var_bounds.shape, var_bounds),<EOL>nullspace=shared_np_array(nulls.shape, nulls),<EOL>homogeneous=homogeneous<EOL>)<EOL>

Build the matrix representation of the sampling problem.


self.n_warmup = <NUM_LIT:0><EOL>reactions = self.model.reactions<EOL>self.warmup = np.zeros((<NUM_LIT:2> * len(reactions), len(self.model.variables)))<EOL>self.model.objective = Zero<EOL>for sense in ("<STR_LIT>", "<STR_LIT>"):<EOL><INDENT>self.model.objective_direction = sense<EOL>for i, r in enumerate(reactions):<EOL><INDENT>variables = (self.model.variables[self.fwd_idx[i]],<EOL>self.model.variables[self.rev_idx[i]])<EOL>if r.upper_bound - r.lower_bound < self.bounds_tol:<EOL><INDENT>LOGGER.info("<STR_LIT>" % r.id)<EOL>continue<EOL><DEDENT>self.model.objective.set_linear_coefficients(<EOL>{variables[<NUM_LIT:0>]: <NUM_LIT:1>, variables[<NUM_LIT:1>]: -<NUM_LIT:1>})<EOL>self.model.slim_optimize()<EOL>if not self.model.solver.status == OPTIMAL:<EOL><INDENT>LOGGER.info("<STR_LIT>" %<EOL>r.id)<EOL>continue<EOL><DEDENT>primals = self.model.solver.primal_values<EOL>sol = [primals[v.name] for v in self.model.variables]<EOL>self.warmup[self.n_warmup, ] = sol<EOL>self.n_warmup += <NUM_LIT:1><EOL>self.model.objective.set_linear_coefficients(<EOL>{variables[<NUM_LIT:0>]: <NUM_LIT:0>, variables[<NUM_LIT:1>]: <NUM_LIT:0>})<EOL><DEDENT><DEDENT>self.warmup = self.warmup[<NUM_LIT:0>:self.n_warmup, :]<EOL>keep = np.logical_not(self._is_redundant(self.warmup))<EOL>self.warmup = self.warmup[keep, :]<EOL>self.n_warmup = self.warmup.shape[<NUM_LIT:0>]<EOL>if len(self.warmup.shape) == <NUM_LIT:1> or self.warmup.shape[<NUM_LIT:0>] == <NUM_LIT:1>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>elif self.n_warmup == <NUM_LIT:2>:<EOL><INDENT>if not self.problem.homogeneous:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>LOGGER.info("<STR_LIT>")<EOL>newdir = self.warmup.T.dot([<NUM_LIT>, <NUM_LIT>])<EOL>self.warmup = np.vstack([self.warmup, newdir])<EOL>self.n_warmup += <NUM_LIT:1><EOL><DEDENT>self.warmup = shared_np_array(<EOL>(self.n_warmup, len(self.model.variables)), self.warmup)<EOL>

Generate the warmup points for the sampler.

        Generates warmup points by setting each flux as the sole objective
        and minimizing/maximizing it. Also caches the projection of the
        warmup points into the nullspace for non-homogeneous problems (only
        if necessary).


nulls = self.problem.nullspace<EOL>equalities = self.problem.equalities<EOL>if np.allclose(equalities.dot(p), self.problem.b,<EOL>rtol=<NUM_LIT:0>, atol=self.feasibility_tol):<EOL><INDENT>new = p<EOL><DEDENT>else:<EOL><INDENT>LOGGER.info("<STR_LIT>"<EOL>"<STR_LIT>" % self.n_samples)<EOL>new = nulls.dot(nulls.T.dot(p))<EOL><DEDENT>if any(new != p):<EOL><INDENT>LOGGER.info("<STR_LIT>"<EOL>"<STR_LIT>" % self.n_samples)<EOL>new = self._random_point()<EOL><DEDENT>return new<EOL>

Reproject a point into the feasibility region.

        This function is guaranteed to return a new feasible point. However,
        no guarantees in terms of proximity to the original point can be made.

        Parameters
        ----------
        p : numpy.array
            The current sample point.

        Returns
        -------
        numpy.array
            A new feasible point. If `p` was feasible it wil return p.


idx = np.random.randint(self.n_warmup,<EOL>size=min(<NUM_LIT:2>, np.ceil(np.sqrt(self.n_warmup))))<EOL>return self.warmup[idx, :].mean(axis=<NUM_LIT:0>)<EOL>

Find an approximately random point in the flux cone.


def _is_redundant(self, matrix, cutoff=None):

cutoff = <NUM_LIT:1.0> - self.feasibility_tol<EOL>extra_col = matrix[:, <NUM_LIT:0>] + <NUM_LIT:1><EOL>extra_col[matrix.sum(axis=<NUM_LIT:1>) == <NUM_LIT:0>] = <NUM_LIT:2><EOL>corr = np.corrcoef(np.c_[matrix, extra_col])<EOL>corr = np.tril(corr, -<NUM_LIT:1>)<EOL>return (np.abs(corr) > cutoff).any(axis=<NUM_LIT:1>)<EOL>

Identify rdeundant rows in a matrix that can be removed.


prob = self.problem<EOL>lb_dist = (p - prob.variable_bounds[<NUM_LIT:0>, ]).min()<EOL>ub_dist = (prob.variable_bounds[<NUM_LIT:1>, ] - p).min()<EOL>if prob.bounds.shape[<NUM_LIT:0>] > <NUM_LIT:0>:<EOL><INDENT>const = prob.inequalities.dot(p)<EOL>const_lb_dist = (const - prob.bounds[<NUM_LIT:0>, ]).min()<EOL>const_ub_dist = (prob.bounds[<NUM_LIT:1>, ] - const).min()<EOL>lb_dist = min(lb_dist, const_lb_dist)<EOL>ub_dist = min(ub_dist, const_ub_dist)<EOL><DEDENT>return np.array([lb_dist, ub_dist])<EOL>

Get the lower and upper bound distances. Negative is bad.


pass<EOL>

Abstract sampling function.

        Should be overwritten by child classes.


def batch(self, batch_size, batch_num, fluxes=True):

for i in range(batch_num):<EOL><INDENT>yield self.sample(batch_size, fluxes=fluxes)<EOL><DEDENT>

Create a batch generator.

        This is useful to generate n batches of m samples each.

        Parameters
        ----------
        batch_size : int
            The number of samples contained in each batch (m).
        batch_num : int
            The number of batches in the generator (n).
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Yields
        ------
        pandas.DataFrame
            A DataFrame with dimensions (batch_size x n_r) containing
            a valid flux sample for a total of n_r reactions (or variables if
            fluxes=False) in each row.


samples = np.atleast_2d(samples)<EOL>prob = self.problem<EOL>if samples.shape[<NUM_LIT:1>] == len(self.model.reactions):<EOL><INDENT>S = create_stoichiometric_matrix(self.model)<EOL>b = np.array([self.model.constraints[m.id].lb for m in<EOL>self.model.metabolites])<EOL>bounds = np.array([r.bounds for r in self.model.reactions]).T<EOL><DEDENT>elif samples.shape[<NUM_LIT:1>] == len(self.model.variables):<EOL><INDENT>S = prob.equalities<EOL>b = prob.b<EOL>bounds = prob.variable_bounds<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>feasibility = np.abs(S.dot(samples.T).T - b).max(axis=<NUM_LIT:1>)<EOL>lb_error = (samples - bounds[<NUM_LIT:0>, ]).min(axis=<NUM_LIT:1>)<EOL>ub_error = (bounds[<NUM_LIT:1>, ] - samples).min(axis=<NUM_LIT:1>)<EOL>if (samples.shape[<NUM_LIT:1>] == len(self.model.variables) and<EOL>prob.inequalities.shape[<NUM_LIT:0>]):<EOL><INDENT>consts = prob.inequalities.dot(samples.T)<EOL>lb_error = np.minimum(<EOL>lb_error,<EOL>(consts - prob.bounds[<NUM_LIT:0>, ]).min(axis=<NUM_LIT:1>))<EOL>ub_error = np.minimum(<EOL>ub_error,<EOL>(prob.bounds[<NUM_LIT:1>, ] - consts).min(axis=<NUM_LIT:1>)<EOL>)<EOL><DEDENT>valid = (<EOL>(feasibility < self.feasibility_tol) &<EOL>(lb_error > -self.bounds_tol) &<EOL>(ub_error > -self.bounds_tol))<EOL>codes = np.repeat("<STR_LIT>", valid.shape[<NUM_LIT:0>]).astype(np.dtype((str, <NUM_LIT:3>)))<EOL>codes[valid] = "<STR_LIT:v>"<EOL>codes[lb_error <= -self.bounds_tol] = np.char.add(<EOL>codes[lb_error <= -self.bounds_tol], "<STR_LIT:l>")<EOL>codes[ub_error <= -self.bounds_tol] = np.char.add(<EOL>codes[ub_error <= -self.bounds_tol], "<STR_LIT:u>")<EOL>codes[feasibility > self.feasibility_tol] = np.char.add(<EOL>codes[feasibility > self.feasibility_tol], "<STR_LIT:e>")<EOL>return codes<EOL>

Validate a set of samples for equality and inequality feasibility.

        Can be used to check whether the generated samples and warmup points
        are feasible.

        Parameters
        ----------
        samples : numpy.matrix
            Must be of dimension (n_samples x n_reactions). Contains the
            samples to be validated. Samples must be from fluxes.

        Returns
        -------
        numpy.array
            A one-dimensional numpy array of length containing
            a code of 1 to 3 letters denoting the validation result:

            - 'v' means feasible in bounds and equality constraints
            - 'l' means a lower bound violation
            - 'u' means a lower bound validation
            - 'e' means and equality constraint violation


def __init__(self, model, thinning=<NUM_LIT:100>, nproj=None, seed=None):

super(ACHRSampler, self).__init__(model, thinning, nproj=nproj,<EOL>seed=seed)<EOL>self.generate_fva_warmup()<EOL>self.prev = self.center = self.warmup.mean(axis=<NUM_LIT:0>)<EOL>np.random.seed(self._seed)<EOL>


samples = np.zeros((n, self.warmup.shape[<NUM_LIT:1>]))<EOL>for i in range(<NUM_LIT:1>, self.thinning * n + <NUM_LIT:1>):<EOL><INDENT>self.__single_iteration()<EOL>if i % self.thinning == <NUM_LIT:0>:<EOL><INDENT>samples[i//self.thinning - <NUM_LIT:1>, ] = self.prev<EOL><DEDENT><DEDENT>if fluxes:<EOL><INDENT>names = [r.id for r in self.model.reactions]<EOL>return pandas.DataFrame(<EOL>samples[:, self.fwd_idx] - samples[:, self.rev_idx],<EOL>columns=names)<EOL><DEDENT>else:<EOL><INDENT>names = [v.name for v in self.model.variables]<EOL>return pandas.DataFrame(samples, columns=names)<EOL><DEDENT>

Generate a set of samples.

        This is the basic sampling function for all hit-and-run samplers.

        Parameters
        ----------
        n : int
            The number of samples that are generated at once.
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Returns
        -------
        numpy.matrix
            Returns a matrix with `n` rows, each containing a flux sample.

        Notes
        -----
        Performance of this function linearly depends on the number
        of reactions in your model and the thinning factor.


global sampler<EOL>sampler = obj<EOL>


n, idx = args       <EOL>center = sampler.center<EOL>np.random.seed((sampler._seed + idx) % np.iinfo(np.int32).max)<EOL>pi = np.random.randint(sampler.n_warmup)<EOL>prev = sampler.warmup[pi, ]<EOL>prev = step(sampler, center, prev - center, <NUM_LIT>)<EOL>n_samples = max(sampler.n_samples, <NUM_LIT:1>)<EOL>samples = np.zeros((n, center.shape[<NUM_LIT:0>]))<EOL>for i in range(<NUM_LIT:1>, sampler.thinning * n + <NUM_LIT:1>):<EOL><INDENT>pi = np.random.randint(sampler.n_warmup)<EOL>delta = sampler.warmup[pi, ] - center<EOL>prev = step(sampler, prev, delta)<EOL>if sampler.problem.homogeneous and (<EOL>n_samples * sampler.thinning % sampler.nproj == <NUM_LIT:0>):<EOL><INDENT>prev = sampler._reproject(prev)<EOL>center = sampler._reproject(center)<EOL><DEDENT>if i % sampler.thinning == <NUM_LIT:0>:<EOL><INDENT>samples[i//sampler.thinning - <NUM_LIT:1>, ] = prev<EOL><DEDENT>center = ((n_samples * center) / (n_samples + <NUM_LIT:1>) +<EOL>prev / (n_samples + <NUM_LIT:1>))<EOL>n_samples += <NUM_LIT:1><EOL><DEDENT>return (sampler.retries, samples)<EOL>

Sample a single chain for OptGPSampler.

    center and n_samples are updated locally and forgotten afterwards.


def __init__(self, model, processes=None, thinning=<NUM_LIT:100>, nproj=None,<EOL>seed=None):

super(OptGPSampler, self).__init__(model, thinning, seed=seed)<EOL>self.generate_fva_warmup()<EOL>if processes is None:<EOL><INDENT>self.processes = CONFIGURATION.processes<EOL><DEDENT>else:<EOL><INDENT>self.processes = processes<EOL><DEDENT>self.center = shared_np_array((len(model.variables), ),<EOL>self.warmup.mean(axis=<NUM_LIT:0>))<EOL>


if self.processes > <NUM_LIT:1>:<EOL><INDENT>n_process = np.ceil(n / self.processes).astype(int)<EOL>n = n_process * self.processes<EOL>args = list(zip(<EOL>[n_process] * self.processes, range(self.processes)))<EOL>mp = Pool(self.processes, initializer=mp_init, initargs=(self,))<EOL>results = mp.map(_sample_chain, args, chunksize=<NUM_LIT:1>)<EOL>mp.close()<EOL>mp.join()<EOL>chains = np.vstack([r[<NUM_LIT:1>] for r in results])<EOL>self.retries += sum(r[<NUM_LIT:0>] for r in results)<EOL><DEDENT>else:<EOL><INDENT>mp_init(self)<EOL>results = _sample_chain((n, <NUM_LIT:0>))<EOL>chains = results[<NUM_LIT:1>]<EOL><DEDENT>self.center = (self.n_samples * self.center +<EOL>np.atleast_2d(chains).sum(<NUM_LIT:0>)) / (self.n_samples + n)<EOL>self.n_samples += n<EOL>if fluxes:<EOL><INDENT>names = [r.id for r in self.model.reactions]<EOL>return pandas.DataFrame(<EOL>chains[:, self.fwd_idx] - chains[:, self.rev_idx],<EOL>columns=names)<EOL><DEDENT>else:<EOL><INDENT>names = [v.name for v in self.model.variables]<EOL>return pandas.DataFrame(chains, columns=names)<EOL><DEDENT>

Generate a set of samples.

        This is the basic sampling function for all hit-and-run samplers.

        Paramters
        ---------
        n : int
            The minimum number of samples that are generated at once
            (see Notes).
        fluxes : boolean
            Whether to return fluxes or the internal solver variables. If set
            to False will return a variable for each forward and backward flux
            as well as all additional variables you might have defined in the
            model.

        Returns
        -------
        numpy.matrix
            Returns a matrix with `n` rows, each containing a flux sample.

        Notes
        -----
        Performance of this function linearly depends on the number
        of reactions in your model and the thinning factor.

        If the number of processes is larger than one, computation is split
        across as the CPUs of your machine. This may shorten computation time.
        However, there is also overhead in setting up parallel computation so
        we recommend to calculate large numbers of samples at once
        (`n` > 1000).


d = dict(self.__dict__)<EOL>del d['<STR_LIT>']<EOL>return d<EOL>


def sample(model, n, method="<STR_LIT>", thinning=<NUM_LIT:100>, processes=<NUM_LIT:1>, seed=None):

if method == "<STR_LIT>":<EOL><INDENT>sampler = OptGPSampler(model, processes, thinning=thinning, seed=seed)<EOL><DEDENT>elif method == "<STR_LIT>":<EOL><INDENT>sampler = ACHRSampler(model, thinning=thinning, seed=seed)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>return pandas.DataFrame(columns=[rxn.id for rxn in model.reactions],<EOL>data=sampler.sample(n))<EOL>

Sample valid flux distributions from a cobra model.

    The function samples valid flux distributions from a cobra model.
    Currently we support two methods:

    1. 'optgp' (default) which uses the OptGPSampler that supports parallel
        sampling [1]_. Requires large numbers of samples to be performant
        (n < 1000). For smaller samples 'achr' might be better suited.

    or

    2. 'achr' which uses artificial centering hit-and-run. This is a single
       process method with good convergence [2]_.

    Parameters
    ----------
    model : cobra.Model
        The model from which to sample flux distributions.
    n : int
        The number of samples to obtain. When using 'optgp' this must be a
        multiple of `processes`, otherwise a larger number of samples will be
        returned.
    method : str, optional
        The sampling algorithm to use.
    thinning : int, optional
        The thinning factor of the generated sampling chain. A thinning of 10
        means samples are returned every 10 steps. Defaults to 100 which in
        benchmarks gives approximately uncorrelated samples. If set to one
        will return all iterates.
    processes : int, optional
        Only used for 'optgp'. The number of processes used to generate
        samples.
    seed : int > 0, optional
        The random number seed to be used. Initialized to current time stamp
        if None.

    Returns
    -------
    pandas.DataFrame
        The generated flux samples. Each row corresponds to a sample of the
        fluxes and the columns are the reactions.

    Notes
    -----
    The samplers have a correction method to ensure equality feasibility for
    long-running chains, however this will only work for homogeneous models,
    meaning models with no non-zero fixed variables or constraints (
    right-hand side of the equalities are zero).

    References
    ----------
    .. [1] Megchelenbrink W, Huynen M, Marchiori E (2014)
       optGpSampler: An Improved Tool for Uniformly Sampling the Solution-Space
       of Genome-Scale Metabolic Networks.
       PLoS ONE 9(2): e86587.
    .. [2] Direction Choice for Accelerated Convergence in Hit-and-Run Sampling
       David E. Kaufman Robert L. Smith
       Operations Research 199846:1 , 84-95


def line_filter(line):<EOL><INDENT>if len(line) == <NUM_LIT:0>:<EOL><INDENT>return True<EOL><DEDENT>return any(line.startswith(c) for c in "<STR_LIT>")<EOL><DEDENT>if len(lines) <= break_pos:<EOL><INDENT>return lines<EOL><DEDENT>newlines = [<EOL>i for i, line in enumerate(lines[break_pos:], start=break_pos)<EOL>if line_filter(line.strip())]<EOL>if len(newlines) > <NUM_LIT:0>:<EOL><INDENT>break_pos = newlines[<NUM_LIT:0>]<EOL><DEDENT>lines.insert(break_pos, "<STR_LIT>")<EOL>return lines<EOL>

Insert a <!--more--> tag for larger release notes.

Parameters
----------
lines : list of str
    The content of the release note.
break_pos : int
    Line number before which a break should approximately be inserted.

Returns
-------
list of str
    The text with the inserted tag or no modification if it was
    sufficiently short.


header = [<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'.format(date.today().isoformat()),<EOL>'<STR_LIT>'.format(tag),<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'.format(bump),<EOL>'<STR_LIT>',<EOL>'<STR_LIT:\n>'<EOL>]<EOL>with open(filename, "<STR_LIT:r>") as file_h:<EOL><INDENT>content = insert_break(file_h.readlines())<EOL><DEDENT>header.extend(content)<EOL>with open(filename, "<STR_LIT:w>") as file_h:<EOL><INDENT>file_h.writelines(header)<EOL><DEDENT>

Build the markdown release notes for Hugo.

Inserts the required TOML header with specific values and adds a break
for long release notes.

Parameters
----------
filename : str, path
    The release notes file.
tag : str
    The tag, following semantic versioning, of the current release.
bump : {"major", "minor", "patch", "alpha", "beta"}
    The type of release.


tmp = filename[:-<NUM_LIT:3>].split("<STR_LIT:.>")<EOL>return int(tmp[<NUM_LIT:0>]), int(tmp[<NUM_LIT:1>])<EOL>

Turn a release note filename into something sortable.

Parameters
----------
filename : str
    A release note of expected filename format '<major>.<minor>.<patch>.md'.

Returns
-------
tuple
    A pair of the major and minor versions as integers.


tmp = tag.split("<STR_LIT:.>")<EOL>existing = [intify(basename(f)) for f in glob(join(target, "<STR_LIT>"))]<EOL>latest = max(existing)<EOL>if int(tmp[<NUM_LIT:0>]) > latest[<NUM_LIT:0>]:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>elif int(tmp[<NUM_LIT:1>]) > latest[<NUM_LIT:1>]:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>return "<STR_LIT>"<EOL><DEDENT>

Identify the kind of release by comparing to existing ones.


source, target, tag = argv<EOL>if "<STR_LIT:a>" in tag:<EOL><INDENT>bump = "<STR_LIT>"<EOL><DEDENT>if "<STR_LIT:b>" in tag:<EOL><INDENT>bump = "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>bump = find_bump(target, tag)<EOL><DEDENT>filename = "<STR_LIT>".format(tag)<EOL>destination = copy(join(source, filename), target)<EOL>build_hugo_md(destination, tag, bump)<EOL>

Identify the release type and create a new target file with TOML header.

Requires three arguments.


created = kwargs.get("<STR_LIT>", False)<EOL>user_instance = kwargs.get("<STR_LIT>", None)<EOL>if user_instance is None:<EOL><INDENT>return  <EOL><DEDENT>try:<EOL><INDENT>pending_ecu = PendingEnterpriseCustomerUser.objects.get(user_email=user_instance.email)<EOL><DEDENT>except PendingEnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>return  <EOL><DEDENT>if not created:<EOL><INDENT>try:<EOL><INDENT>existing_record = EnterpriseCustomerUser.objects.get(user_id=user_instance.id)<EOL>message_template = "<STR_LIT>""<STR_LIT>""<STR_LIT>"<EOL>logger.info(message_template.format(<EOL>user=user_instance, enterprise_customer=existing_record.enterprise_customer<EOL>))<EOL>pending_ecu.delete()<EOL>return<EOL><DEDENT>except EnterpriseCustomerUser.DoesNotExist:<EOL><INDENT>pass  <EOL><DEDENT><DEDENT>enterprise_customer_user = EnterpriseCustomerUser.objects.create(<EOL>enterprise_customer=pending_ecu.enterprise_customer,<EOL>user_id=user_instance.id<EOL>)<EOL>pending_enrollments = list(pending_ecu.pendingenrollment_set.all())<EOL>if pending_enrollments:<EOL><INDENT>def _complete_user_enrollment():  <EOL><INDENT>for enrollment in pending_enrollments:<EOL><INDENT>enterprise_customer_user.enroll(<EOL>enrollment.course_id, enrollment.course_mode, cohort=enrollment.cohort_name)<EOL>track_enrollment('<STR_LIT>', user_instance.id, enrollment.course_id)<EOL><DEDENT>pending_ecu.delete()<EOL><DEDENT>transaction.on_commit(_complete_user_enrollment)<EOL><DEDENT>else:<EOL><INDENT>pending_ecu.delete()<EOL><DEDENT>

Handle User model changes - checks if pending enterprise customer user record exists and upgrades it to actual link.

If there are pending enrollments attached to the PendingEnterpriseCustomerUser, then this signal also takes the
newly-created users and enrolls them in the relevant courses.


@receiver(post_save, sender=EnterpriseCustomerCatalog, dispatch_uid='<STR_LIT>')<EOL>def default_content_filter(sender, instance, **kwargs):

if kwargs['<STR_LIT>'] and not instance.content_filter:<EOL><INDENT>instance.content_filter = get_default_catalog_content_filter()<EOL>instance.save()<EOL><DEDENT>

Set default value for `EnterpriseCustomerCatalog.content_filter` if not already set.


@receiver(post_save, sender=EnterpriseCustomerUser)<EOL>def assign_enterprise_learner_role(sender, instance, **kwargs):

if kwargs['<STR_LIT>'] and instance.user:<EOL><INDENT>enterprise_learner_role, __ = SystemWideEnterpriseRole.objects.get_or_create(name=ENTERPRISE_LEARNER_ROLE)<EOL>SystemWideEnterpriseUserRoleAssignment.objects.get_or_create(<EOL>user=instance.user,<EOL>role=enterprise_learner_role<EOL>)<EOL><DEDENT>

Assign an enterprise learner role to EnterpriseCustomerUser whenever a new record is created.


@receiver(post_delete, sender=EnterpriseCustomerUser)<EOL>def delete_enterprise_learner_role_assignment(sender, instance, **kwargs):

Delete the associated enterprise learner role assignment record when deleting an EnterpriseCustomerUser record.


return {<EOL>'<STR_LIT>': MESSAGE_ICONS.get(message_type, '<STR_LIT>'.format(message_type))<EOL>}<EOL>

Django template tag that returns font awesome icon depending upon message type.

Usage:
    {% fa_icon "success" %}


return {<EOL>'<STR_LIT>': messages<EOL>}<EOL>

Django template tag that returns an alert message.

Usage:
    {% alert_messages messages %}


@register.inclusion_tag('<STR_LIT>', takes_context=True)<EOL>def course_modal(context, course=None):

if course:<EOL><INDENT>context.update({<EOL>'<STR_LIT>': course.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course.get('<STR_LIT>', []),<EOL>'<STR_LIT>': course.get('<STR_LIT>', []),<EOL>'<STR_LIT>': course.get('<STR_LIT>', []),<EOL>})<EOL><DEDENT>return context<EOL>

Django template tag that returns course information to display in a modal.

You may pass in a particular course if you like. Otherwise, the modal will look for course context
within the parent context.

Usage:
    {% course_modal %}
    {% course_modal course %}


return {<EOL>'<STR_LIT:value>': value,<EOL>'<STR_LIT>': href,<EOL>}<EOL>

Django template tag that returns a button used to expand/collapse a container.

You may pass in the ID of the container that this button controls, and a button text value.

Usage:
    {% expand_button 'Click me!' '#id' %}


@register.filter(needs_autoescape=True)<EOL>def link_to_modal(link_text, index, autoescape=True):

Django template filter that returns an anchor with attributes useful for course modal selection.

General Usage:
    {{ link_text|link_to_modal:index }}

Examples:
    {{ course_title|link_to_modal:forloop.counter0 }}
    {{ course_title|link_to_modal:3 }}
    {{ view_details_text|link_to_modal:0 }}


return mark_safe(strip_html_tags(html_text))<EOL>

Django template filter that strips all HTML tags excepts those degined in ALLOWED_TAGS.

General Usage:
    {{ html_text|only_safe_html }}


Switch = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>Switch.objects.update_or_create(name=ENTERPRISE_ROLE_BASED_ACCESS_CONTROL_SWITCH, defaults={'<STR_LIT>': False})<EOL>

Create the `role_based_access_control` switch if it does not already exist.


Switch = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>Switch.objects.filter(name=ENTERPRISE_ROLE_BASED_ACCESS_CONTROL_SWITCH).delete()<EOL>

Delete the `role_based_access_control` switch.


Create the enterprise roles if they do not already exist.


EnterpriseFeatureRole = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>EnterpriseFeatureRole.objects.filter(<EOL>name__in=[ENTERPRISE_CATALOG_ADMIN_ROLE, ENTERPRISE_DASHBOARD_ADMIN_ROLE, ENTERPRISE_ENROLLMENT_API_ADMIN_ROLE]<EOL>).delete()<EOL>


SystemWideEnterpriseRole = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>SystemWideEnterpriseRole.objects.filter(<EOL>name__in=[ENTERPRISE_ADMIN_ROLE, ENTERPRISE_LEARNER_ROLE]<EOL>).delete()<EOL>


SystemWideEnterpriseRole = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>SystemWideEnterpriseRole.objects.update_or_create(name=ENTERPRISE_OPERATOR_ROLE)<EOL>


SystemWideEnterpriseRole = apps.get_model('<STR_LIT>', '<STR_LIT>')<EOL>SystemWideEnterpriseRole.objects.filter(<EOL>name__in=[ENTERPRISE_OPERATOR_ROLE]<EOL>).delete()<EOL>


return apps.get_app_config("<STR_LIT>")<EOL>


config = get_app_config()<EOL>ext = os.path.splitext(value.name)[<NUM_LIT:1>]<EOL>if config and not ext.lower() in config.valid_image_extensions:<EOL><INDENT>raise ValidationError(_("<STR_LIT>"))<EOL><DEDENT>

Validate that a particular image extension.


config = get_app_config()<EOL>valid_max_image_size_in_bytes = config.valid_max_image_size * <NUM_LIT><EOL>if config and not image.size <= valid_max_image_size_in_bytes:<EOL><INDENT>raise ValidationError(<EOL>_("<STR_LIT>") % config.valid_max_image_size)<EOL><DEDENT>


required_methods = {<EOL>'<STR_LIT>': ProgramDataExtender,<EOL>}<EOL>for method in required_methods:<EOL><INDENT>if required_methods[method] is None:<EOL><INDENT>raise NotConnectedToOpenEdX(<EOL>_("<STR_LIT>")<EOL>+ "<STR_LIT>".format(method=method)<EOL>)<EOL><DEDENT><DEDENT>

Ensure that all necessary resources to render the view are present.


Get the set of variables that are needed by default across views.


if waffle.switch_is_active('<STR_LIT>') and get_localized_price_text:<EOL><INDENT>return get_localized_price_text(price, request)<EOL><DEDENT>return format_price(price)<EOL>

Return the localized converted price as string (ex. '$150 USD').

If the local_currency switch is enabled and the users location has been determined this will convert the
given price based on conversion rate from the Catalog service and return a localized string


def render_page_with_error_code_message(request, context_data, error_code, log_message):

Return a 404 page with specified error_code after logging error and adding message to django messages.


@method_decorator(transaction.non_atomic_requests)<EOL><INDENT>def dispatch(self, request, *args, **kwargs):<DEDENT>

return super(NonAtomicView, self).dispatch(request, *args, **kwargs)<EOL>

Disable atomicity for the view.

Since we have settings.ATOMIC_REQUESTS enabled, Django wraps all view functions in an atomic transaction, so
they can be rolled back if anything fails.

However, we need to be able to save data in the middle of get/post(), so that it's available for calls to
external APIs.  To allow this, we need to disable atomicity at the top dispatch level.


def course_or_program_exist(self, course_id, program_uuid):

course_exists = course_id and CourseApiClient().get_course_details(course_id)<EOL>program_exists = program_uuid and CourseCatalogApiServiceClient().program_exists(program_uuid)<EOL>return course_exists or program_exists<EOL>

Return whether the input course or program exist.


def get_default_context(self, enterprise_customer, platform_name):

Get the set of variables that will populate the template by default.


def get_context_from_db(self, consent_page, platform_name, item, context):

Make set of variables(populated from db) that will be used in data sharing consent page.


def get_course_or_program_context(self, enterprise_customer, course_id=None, program_uuid=None):

context_data = {}<EOL>if course_id:<EOL><INDENT>context_data.update({'<STR_LIT>': course_id, '<STR_LIT>': True})<EOL>if not self.preview_mode:<EOL><INDENT>try:<EOL><INDENT>catalog_api_client = CourseCatalogApiServiceClient(enterprise_customer.site)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>raise Http404<EOL><DEDENT>course_run_details = catalog_api_client.get_course_run(course_id)<EOL>course_start_date = '<STR_LIT>'<EOL>if course_run_details['<STR_LIT:start>']:<EOL><INDENT>course_start_date = parse(course_run_details['<STR_LIT:start>']).strftime('<STR_LIT>')<EOL><DEDENT>context_data.update({<EOL>'<STR_LIT>': course_run_details['<STR_LIT:title>'],<EOL>'<STR_LIT>': course_start_date,<EOL>})<EOL><DEDENT>else:<EOL><INDENT>context_data.update({<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': datetime.datetime.now().strftime('<STR_LIT>'),<EOL>})<EOL><DEDENT><DEDENT>else:<EOL><INDENT>context_data.update({<EOL>'<STR_LIT>': program_uuid,<EOL>'<STR_LIT>': True,<EOL>})<EOL><DEDENT>return context_data<EOL>

Return a dict having course or program specific keys for data sharing consent page.


enterprise_customer_uuid = request.GET.get('<STR_LIT>')<EOL>success_url = request.GET.get('<STR_LIT>')<EOL>failure_url = request.GET.get('<STR_LIT>')<EOL>course_id = request.GET.get('<STR_LIT>', '<STR_LIT>')<EOL>program_uuid = request.GET.get('<STR_LIT>', '<STR_LIT>')<EOL>self.preview_mode = bool(request.GET.get('<STR_LIT>', False))<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_customer_uuid)<EOL>context_data = get_global_context(request, enterprise_customer)<EOL>if not self.preview_mode:<EOL><INDENT>if not self.course_or_program_exist(course_id, program_uuid):<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_id=course_id,<EOL>program_uuid=program_uuid,<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>try:<EOL><INDENT>consent_record = get_data_sharing_consent(<EOL>request.user.username,<EOL>enterprise_customer_uuid,<EOL>program_uuid=program_uuid,<EOL>course_id=course_id<EOL>)<EOL><DEDENT>except NotConnectedToOpenEdX as error:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>error=error,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>try:<EOL><INDENT>consent_required = consent_record.consent_required()<EOL><DEDENT>except AttributeError:<EOL><INDENT>consent_required = None<EOL><DEDENT>if consent_record is None or not consent_required:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>consent_record=consent_record,<EOL>consent_required=consent_required,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>else:<EOL><INDENT>enterprise_customer = consent_record.enterprise_customer<EOL><DEDENT><DEDENT>elif not request.user.is_staff:<EOL><INDENT>raise PermissionDenied()<EOL><DEDENT>context_data = get_global_context(request, enterprise_customer)<EOL>if not (enterprise_customer_uuid and success_url and failure_url):<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>success_url=success_url,<EOL>failure_url=failure_url,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>try:<EOL><INDENT>updated_context_dict = self.get_course_or_program_context(<EOL>enterprise_customer,<EOL>course_id=course_id,<EOL>program_uuid=program_uuid<EOL>)<EOL>context_data.update(updated_context_dict)<EOL><DEDENT>except Http404:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>item = '<STR_LIT>' if course_id else '<STR_LIT>'<EOL>context_data.update({<EOL>'<STR_LIT>': _(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>).format(<EOL>enterprise_customer_name=enterprise_customer.name,<EOL>bold_start='<STR_LIT>',<EOL>bold_end='<STR_LIT>',<EOL>item=item,<EOL>),<EOL>'<STR_LIT>': _(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>).format(<EOL>enterprise_customer_name=enterprise_customer.name,<EOL>bold_start='<STR_LIT>',<EOL>bold_end='<STR_LIT>',<EOL>item=item,<EOL>),<EOL>'<STR_LIT>': success_url,<EOL>'<STR_LIT>': failure_url,<EOL>'<STR_LIT>': request.GET.get('<STR_LIT>') is not None,<EOL>'<STR_LIT>': [<EOL>_('<STR_LIT>').format(item=item),<EOL>_('<STR_LIT>'),<EOL>_('<STR_LIT>'),<EOL>],<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>})<EOL>platform_name = context_data['<STR_LIT>']<EOL>published_only = False if self.preview_mode else True<EOL>enterprise_consent_page = enterprise_customer.get_data_sharing_consent_text_overrides(<EOL>published_only=published_only<EOL>)<EOL>if enterprise_consent_page:<EOL><INDENT>context_data.update(self.get_context_from_db(enterprise_consent_page, platform_name, item, context_data))<EOL><DEDENT>else:<EOL><INDENT>context_data.update(self.get_default_context(enterprise_customer, platform_name))<EOL><DEDENT>return render(request, '<STR_LIT>', context=context_data)<EOL>

Render a form to collect user input about data sharing consent.


enterprise_uuid = request.POST.get('<STR_LIT>')<EOL>success_url = request.POST.get('<STR_LIT>')<EOL>failure_url = request.POST.get('<STR_LIT>')<EOL>course_id = request.POST.get('<STR_LIT>', '<STR_LIT>')<EOL>program_uuid = request.POST.get('<STR_LIT>', '<STR_LIT>')<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>context_data = get_global_context(request, enterprise_customer)<EOL>if not (enterprise_uuid and success_url and failure_url):<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_uuid=enterprise_uuid,<EOL>success_url=success_url,<EOL>failure_url=failure_url,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>if not self.course_or_program_exist(course_id, program_uuid):<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_id=course_id,<EOL>program_uuid=program_uuid,<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_uuid=enterprise_uuid,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>consent_record = get_data_sharing_consent(<EOL>request.user.username,<EOL>enterprise_uuid,<EOL>program_uuid=program_uuid,<EOL>course_id=course_id<EOL>)<EOL>if consent_record is None:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_uuid=enterprise_uuid,<EOL>consent_record=consent_record,<EOL>error_code=error_code,<EOL>course_id=course_id,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>defer_creation = request.POST.get('<STR_LIT>')<EOL>consent_provided = bool(request.POST.get('<STR_LIT>', False))<EOL>if defer_creation is None and consent_record.consent_required():<EOL><INDENT>if course_id:<EOL><INDENT>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=consent_record.enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL>__, created = EnterpriseCourseEnrollment.objects.get_or_create(<EOL>enterprise_customer_user=enterprise_customer_user,<EOL>course_id=course_id,<EOL>)<EOL>if created:<EOL><INDENT>track_enrollment('<STR_LIT>', request.user.id, course_id, request.path)<EOL><DEDENT><DEDENT>consent_record.granted = consent_provided<EOL>consent_record.save()<EOL><DEDENT>return redirect(success_url if consent_provided else failure_url)<EOL>


@method_decorator(enterprise_login_required)<EOL><INDENT>def get(self, request, enterprise_uuid, course_id):<DEDENT>

enrollment_course_mode = request.GET.get('<STR_LIT>')<EOL>enterprise_catalog_uuid = request.GET.get('<STR_LIT>')<EOL>if not enrollment_course_mode:<EOL><INDENT>return redirect(LMS_DASHBOARD_URL)<EOL><DEDENT>enrollment_api_client = EnrollmentApiClient()<EOL>course_modes = enrollment_api_client.get_course_modes(course_id)<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>enterprise_customer_user = get_enterprise_customer_user(request.user.id, enterprise_customer.uuid)<EOL>if not course_modes:<EOL><INDENT>context_data = get_global_context(request, enterprise_customer)<EOL>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_catalog_uuid=enterprise_catalog_uuid,<EOL>course_id=course_id,<EOL>error_code=error_code<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>selected_course_mode = None<EOL>for course_mode in course_modes:<EOL><INDENT>if course_mode['<STR_LIT>'] == enrollment_course_mode:<EOL><INDENT>selected_course_mode = course_mode<EOL>break<EOL><DEDENT><DEDENT>if not selected_course_mode:<EOL><INDENT>return redirect(LMS_DASHBOARD_URL)<EOL><DEDENT>__, created = EnterpriseCourseEnrollment.objects.get_or_create(<EOL>enterprise_customer_user=enterprise_customer_user,<EOL>course_id=course_id,<EOL>)<EOL>if created:<EOL><INDENT>track_enrollment('<STR_LIT>', request.user.id, course_id, request.get_full_path())<EOL><DEDENT>DataSharingConsent.objects.update_or_create(<EOL>username=enterprise_customer_user.username,<EOL>course_id=course_id,<EOL>enterprise_customer=enterprise_customer_user.enterprise_customer,<EOL>defaults={<EOL>'<STR_LIT>': True<EOL>},<EOL>)<EOL>audit_modes = getattr(settings, '<STR_LIT>', ['<STR_LIT>', '<STR_LIT>'])<EOL>if selected_course_mode['<STR_LIT>'] in audit_modes:<EOL><INDENT>enrollment_api_client.enroll_user_in_course(<EOL>request.user.username, course_id, selected_course_mode['<STR_LIT>']<EOL>)<EOL>return redirect(LMS_COURSEWARE_URL.format(course_id=course_id))<EOL><DEDENT>premium_flow = LMS_START_PREMIUM_COURSE_FLOW_URL.format(course_id=course_id)<EOL>if enterprise_catalog_uuid:<EOL><INDENT>premium_flow += '<STR_LIT>'.format(<EOL>catalog_uuid=enterprise_catalog_uuid<EOL>)<EOL><DEDENT>return redirect(premium_flow)<EOL>

Handle the enrollment of enterprise learner in the provided course.

Based on `enterprise_uuid` in URL, the view will decide which
enterprise customer's course enrollment record should be created.

Depending on the value of query parameter `course_mode` then learner
will be either redirected to LMS dashboard for audit modes or
redirected to ecommerce basket flow for payment of premium modes.


def set_final_prices(self, modes, request):

result = []<EOL>for mode in modes:<EOL><INDENT>if mode['<STR_LIT>']:<EOL><INDENT>mode['<STR_LIT>'] = EcommerceApiClient(request.user).get_course_final_price(<EOL>mode=mode,<EOL>enterprise_catalog_uuid=request.GET.get(<EOL>'<STR_LIT>'<EOL>) if request.method == '<STR_LIT:GET>' else None,<EOL>)<EOL><DEDENT>result.append(mode)<EOL><DEDENT>return result<EOL>

Set the final discounted price on each premium mode.


def get_available_course_modes(self, request, course_run_id, enterprise_catalog):

modes = EnrollmentApiClient().get_course_modes(course_run_id)<EOL>if not modes:<EOL><INDENT>LOGGER.warning('<STR_LIT>'.format(<EOL>course_run_id=course_run_id<EOL>))<EOL>messages.add_generic_info_message_for_error(request)<EOL><DEDENT>if enterprise_catalog:<EOL><INDENT>modes = [mode for mode in modes if mode['<STR_LIT>'] in enterprise_catalog.enabled_course_modes]<EOL>modes.sort(key=lambda course_mode: enterprise_catalog.enabled_course_modes.index(course_mode['<STR_LIT>']))<EOL>if not modes:<EOL><INDENT>LOGGER.info(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_run_id=course_run_id,<EOL>enterprise_catalog_uuid=enterprise_catalog,<EOL>)<EOL>)<EOL>messages.add_generic_info_message_for_error(request)<EOL><DEDENT><DEDENT>return modes<EOL>

Return the available course modes for the course run.

The provided EnterpriseCustomerCatalog is used to filter and order the
course modes returned using the EnterpriseCustomerCatalog's
field "enabled_course_modes".


def get_base_details(self, request, enterprise_uuid, course_run_id):

enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>enterprise_catalog_uuid = request.GET.get('<STR_LIT>')<EOL>enterprise_catalog = None<EOL>if enterprise_catalog_uuid:<EOL><INDENT>try:<EOL><INDENT>enterprise_catalog_uuid = UUID(enterprise_catalog_uuid)<EOL>enterprise_catalog = enterprise_customer.enterprise_customer_catalogs.get(<EOL>uuid=enterprise_catalog_uuid<EOL>)<EOL><DEDENT>except (ValueError, EnterpriseCustomerCatalog.DoesNotExist):<EOL><INDENT>LOGGER.warning(<EOL>'<STR_LIT>'.format(<EOL>enterprise_catalog_uuid=enterprise_catalog_uuid,<EOL>)<EOL>)<EOL>messages.add_generic_info_message_for_error(request)<EOL><DEDENT><DEDENT>course = None<EOL>course_run = None<EOL>course_modes = []<EOL>if enterprise_catalog:<EOL><INDENT>course, course_run = enterprise_catalog.get_course_and_course_run(course_run_id)<EOL><DEDENT>else:<EOL><INDENT>try:<EOL><INDENT>course, course_run = CourseCatalogApiServiceClient(<EOL>enterprise_customer.site<EOL>).get_course_and_course_run(course_run_id)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>LOGGER.warning('<STR_LIT>')<EOL>messages.add_generic_info_message_for_error(request)<EOL>return enterprise_customer, course, course_run, course_modes<EOL><DEDENT><DEDENT>if not course or not course_run:<EOL><INDENT>course_id = course['<STR_LIT:key>'] if course else "<STR_LIT>"<EOL>course_title = course['<STR_LIT:title>'] if course else "<STR_LIT>"<EOL>course_run_title = course_run['<STR_LIT:title>'] if course_run else "<STR_LIT>"<EOL>enterprise_catalog_title = enterprise_catalog.title if enterprise_catalog else "<STR_LIT>"<EOL>LOGGER.warning(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_title=course_title,<EOL>course_id=course_id,<EOL>course_run_title=course_run_title,<EOL>course_run_id=course_run_id,<EOL>enterprise_name=enterprise_customer.name,<EOL>enterprise_uuid=enterprise_customer.uuid,<EOL>enterprise_catalog_title=enterprise_catalog_title,<EOL>enterprise_catalog_uuid=enterprise_catalog_uuid,<EOL>)<EOL>)<EOL>messages.add_generic_info_message_for_error(request)<EOL>return enterprise_customer, course, course_run, course_modes<EOL><DEDENT>if enterprise_catalog_uuid and not enterprise_catalog:<EOL><INDENT>return enterprise_customer, course, course_run, course_modes<EOL><DEDENT>modes = self.get_available_course_modes(request, course_run_id, enterprise_catalog)<EOL>audit_modes = getattr(<EOL>settings,<EOL>'<STR_LIT>',<EOL>['<STR_LIT>', '<STR_LIT>']<EOL>)<EOL>for mode in modes:<EOL><INDENT>if mode['<STR_LIT>']:<EOL><INDENT>price_text = get_price_text(mode['<STR_LIT>'], request)<EOL><DEDENT>else:<EOL><INDENT>price_text = _('<STR_LIT>')<EOL><DEDENT>if mode['<STR_LIT>'] in audit_modes:<EOL><INDENT>description = _('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>description = _('<STR_LIT>')<EOL><DEDENT>course_modes.append({<EOL>'<STR_LIT>': mode['<STR_LIT>'],<EOL>'<STR_LIT>': mode['<STR_LIT>'],<EOL>'<STR_LIT>': mode['<STR_LIT>'],<EOL>'<STR_LIT:title>': mode['<STR_LIT:name>'],<EOL>'<STR_LIT>': price_text,<EOL>'<STR_LIT>': price_text,<EOL>'<STR_LIT:description>': description,<EOL>'<STR_LIT>': mode['<STR_LIT>'] not in audit_modes<EOL>})<EOL><DEDENT>return enterprise_customer, course, course_run, course_modes<EOL>

Retrieve fundamental details used by both POST and GET versions of this view.

Specifically, take an EnterpriseCustomer UUID and a course run ID, and transform those
into an actual EnterpriseCustomer, a set of details about the course, and a list
of the available course modes for that course run.


context_data = get_global_context(request, enterprise_customer)<EOL>enterprise_catalog_uuid = request.GET.get(<EOL>'<STR_LIT>'<EOL>) if request.method == '<STR_LIT:GET>' else None<EOL>html_template_for_rendering = ENTERPRISE_GENERAL_ERROR_PAGE<EOL>if course and course_run:<EOL><INDENT>course_enrollable = True<EOL>course_start_date = '<STR_LIT>'<EOL>course_in_future = False<EOL>organization_name = '<STR_LIT>'<EOL>organization_logo = '<STR_LIT>'<EOL>expected_learning_items = course['<STR_LIT>']<EOL>if course['<STR_LIT>']:<EOL><INDENT>organization = course['<STR_LIT>'][<NUM_LIT:0>]<EOL>organization_name = organization['<STR_LIT:name>']<EOL>organization_logo = organization['<STR_LIT>']<EOL><DEDENT>course_title = course_run['<STR_LIT:title>']<EOL>course_short_description = course_run['<STR_LIT>'] or '<STR_LIT>'<EOL>course_full_description = clean_html_for_template_rendering(course_run['<STR_LIT>'] or '<STR_LIT>')<EOL>course_pacing = self.PACING_FORMAT.get(course_run['<STR_LIT>'], '<STR_LIT>')<EOL>if course_run['<STR_LIT:start>']:<EOL><INDENT>course_start_date = parse(course_run['<STR_LIT:start>']).strftime('<STR_LIT>')<EOL>now = datetime.datetime.now(pytz.UTC)<EOL>course_in_future = parse(course_run['<STR_LIT:start>']) > now<EOL><DEDENT>course_level_type = course_run.get('<STR_LIT>', '<STR_LIT>')<EOL>staff = course_run['<STR_LIT>']<EOL>course_effort = ungettext_min_max(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>course_run['<STR_LIT>'] or None,<EOL>course_run['<STR_LIT>'] or None,<EOL>) or '<STR_LIT>'<EOL>course_run_image = course_run['<STR_LIT:image>'] or {}<EOL>course_image_uri = course_run_image.get('<STR_LIT:src>', '<STR_LIT>')<EOL>course_modes = self.set_final_prices(course_modes, request)<EOL>premium_modes = [mode for mode in course_modes if mode['<STR_LIT>']]<EOL>course_modes = filter_audit_course_modes(enterprise_customer, course_modes)<EOL>cohort = request.GET.get('<STR_LIT>')<EOL>if enterprise_course_enrollment and not data_sharing_consent.granted:<EOL><INDENT>messages.add_consent_declined_message(request, enterprise_customer, course_run.get('<STR_LIT:title>', '<STR_LIT>'))<EOL><DEDENT>if not is_course_run_enrollable(course_run):<EOL><INDENT>messages.add_unenrollable_item_message(request, '<STR_LIT>')<EOL>course_enrollable = False<EOL><DEDENT>context_data.update({<EOL>'<STR_LIT>': course_enrollable,<EOL>'<STR_LIT>': course_title,<EOL>'<STR_LIT>': course_short_description,<EOL>'<STR_LIT>': course_pacing,<EOL>'<STR_LIT>': course_start_date,<EOL>'<STR_LIT>': course_in_future,<EOL>'<STR_LIT>': course_image_uri,<EOL>'<STR_LIT>': course_modes,<EOL>'<STR_LIT>': course_effort,<EOL>'<STR_LIT>': course_full_description,<EOL>'<STR_LIT>': cohort,<EOL>'<STR_LIT>': organization_logo,<EOL>'<STR_LIT>': organization_name,<EOL>'<STR_LIT>': course_level_type,<EOL>'<STR_LIT>': premium_modes,<EOL>'<STR_LIT>': expected_learning_items,<EOL>'<STR_LIT>': enterprise_catalog_uuid,<EOL>'<STR_LIT>': staff,<EOL>'<STR_LIT>': _('<STR_LIT>').format(<EOL>enterprise_customer_name=enterprise_customer.name,<EOL>strong_start='<STR_LIT>',<EOL>strong_end='<STR_LIT>',<EOL>),<EOL>'<STR_LIT>': enterprise_customer.hide_course_original_price<EOL>})<EOL>html_template_for_rendering = '<STR_LIT>'<EOL><DEDENT>context_data.update({<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _("<STR_LIT>"),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>})<EOL>return render(request, html_template_for_rendering, context=context_data)<EOL>

Render enterprise-specific course track selection page.


@method_decorator(enterprise_login_required)<EOL><INDENT>def post(self, request, enterprise_uuid, course_id):<DEDENT>

enterprise_customer, course, course_run, course_modes = self.get_base_details(<EOL>request, enterprise_uuid, course_id<EOL>)<EOL>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL>data_sharing_consent = DataSharingConsent.objects.proxied_get(<EOL>username=enterprise_customer_user.username,<EOL>course_id=course_id,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL>try:<EOL><INDENT>enterprise_course_enrollment = EnterpriseCourseEnrollment.objects.get(<EOL>enterprise_customer_user__enterprise_customer=enterprise_customer,<EOL>enterprise_customer_user__user_id=request.user.id,<EOL>course_id=course_id<EOL>)<EOL><DEDENT>except EnterpriseCourseEnrollment.DoesNotExist:<EOL><INDENT>enterprise_course_enrollment = None<EOL><DEDENT>enterprise_catalog_uuid = request.POST.get('<STR_LIT>')<EOL>selected_course_mode_name = request.POST.get('<STR_LIT>')<EOL>cohort_name = request.POST.get('<STR_LIT>')<EOL>selected_course_mode = None<EOL>for course_mode in course_modes:<EOL><INDENT>if course_mode['<STR_LIT>'] == selected_course_mode_name:<EOL><INDENT>selected_course_mode = course_mode<EOL>break<EOL><DEDENT><DEDENT>if not selected_course_mode:<EOL><INDENT>return self.get_enterprise_course_enrollment_page(<EOL>request,<EOL>enterprise_customer,<EOL>course,<EOL>course_run,<EOL>course_modes,<EOL>enterprise_course_enrollment,<EOL>data_sharing_consent<EOL>)<EOL><DEDENT>user_consent_needed = get_data_sharing_consent(<EOL>enterprise_customer_user.username,<EOL>enterprise_customer.uuid,<EOL>course_id=course_id<EOL>).consent_required()<EOL>if not selected_course_mode.get('<STR_LIT>') and not user_consent_needed:<EOL><INDENT>if not enterprise_course_enrollment:<EOL><INDENT>enterprise_course_enrollment = EnterpriseCourseEnrollment.objects.create(<EOL>enterprise_customer_user=enterprise_customer_user,<EOL>course_id=course_id,<EOL>)<EOL>track_enrollment('<STR_LIT>', request.user.id, course_id, request.get_full_path())<EOL><DEDENT>client = EnrollmentApiClient()<EOL>client.enroll_user_in_course(<EOL>request.user.username,<EOL>course_id,<EOL>selected_course_mode_name,<EOL>cohort=cohort_name<EOL>)<EOL>return redirect(LMS_COURSEWARE_URL.format(course_id=course_id))<EOL><DEDENT>if user_consent_needed:<EOL><INDENT>query_string_params = {<EOL>'<STR_LIT>': selected_course_mode_name,<EOL>}<EOL>if enterprise_catalog_uuid:<EOL><INDENT>query_string_params.update({'<STR_LIT>': enterprise_catalog_uuid})<EOL><DEDENT>next_url = '<STR_LIT>'.format(<EOL>handle_consent_enrollment_url=reverse(<EOL>'<STR_LIT>', args=[enterprise_customer.uuid, course_id]<EOL>),<EOL>query_string=urlencode(query_string_params)<EOL>)<EOL>failure_url = reverse('<STR_LIT>', args=[enterprise_customer.uuid, course_id])<EOL>if request.META['<STR_LIT>']:<EOL><INDENT>failure_url = '<STR_LIT>'.format(<EOL>course_enrollment_url=reverse(<EOL>'<STR_LIT>', args=[enterprise_customer.uuid, course_id]<EOL>),<EOL>query_string=request.META['<STR_LIT>']<EOL>)<EOL><DEDENT>return redirect(<EOL>'<STR_LIT>'.format(<EOL>grant_data_sharing_url=reverse('<STR_LIT>'),<EOL>params=urlencode(<EOL>{<EOL>'<STR_LIT>': next_url,<EOL>'<STR_LIT>': failure_url,<EOL>'<STR_LIT>': enterprise_customer.uuid,<EOL>'<STR_LIT>': course_id,<EOL>}<EOL>)<EOL>)<EOL>)<EOL><DEDENT>premium_flow = LMS_START_PREMIUM_COURSE_FLOW_URL.format(course_id=course_id)<EOL>if enterprise_catalog_uuid:<EOL><INDENT>premium_flow += '<STR_LIT>'.format(<EOL>catalog_uuid=enterprise_catalog_uuid<EOL>)<EOL><DEDENT>return redirect(premium_flow)<EOL>

Process a submitted track selection form for the enterprise.


@method_decorator(enterprise_login_required)<EOL><INDENT>@method_decorator(force_fresh_session)<EOL>def get(self, request, enterprise_uuid, course_id):<DEDENT>

<EOL>embargo_url = EmbargoApiClient.redirect_if_blocked([course_id], request.user, get_ip(request), request.path)<EOL>if embargo_url:<EOL><INDENT>return redirect(embargo_url)<EOL><DEDENT>enterprise_customer, course, course_run, modes = self.get_base_details(<EOL>request, enterprise_uuid, course_id<EOL>)<EOL>enterprise_customer_user = get_enterprise_customer_user(request.user.id, enterprise_uuid)<EOL>data_sharing_consent = DataSharingConsent.objects.proxied_get(<EOL>username=enterprise_customer_user.username,<EOL>course_id=course_id,<EOL>enterprise_customer=enterprise_customer<EOL>)<EOL>enrollment_client = EnrollmentApiClient()<EOL>enrolled_course = enrollment_client.get_course_enrollment(request.user.username, course_id)<EOL>try:<EOL><INDENT>enterprise_course_enrollment = EnterpriseCourseEnrollment.objects.get(<EOL>enterprise_customer_user__enterprise_customer=enterprise_customer,<EOL>enterprise_customer_user__user_id=request.user.id,<EOL>course_id=course_id<EOL>)<EOL><DEDENT>except EnterpriseCourseEnrollment.DoesNotExist:<EOL><INDENT>enterprise_course_enrollment = None<EOL><DEDENT>if enrolled_course and enterprise_course_enrollment:<EOL><INDENT>return redirect(LMS_COURSEWARE_URL.format(course_id=course_id))<EOL><DEDENT>return self.get_enterprise_course_enrollment_page(<EOL>request,<EOL>enterprise_customer,<EOL>course,<EOL>course_run,<EOL>modes,<EOL>enterprise_course_enrollment,<EOL>data_sharing_consent,<EOL>)<EOL>

Show course track selection page for the enterprise.

Based on `enterprise_uuid` in URL, the view will decide which
enterprise customer's course enrollment page is to use.

Unauthenticated learners will be redirected to enterprise-linked SSO.

A 404 will be raised if any of the following conditions are met:
    * No enterprise customer uuid kwarg `enterprise_uuid` in request.
    * No enterprise customer found against the enterprise customer
        uuid `enterprise_uuid` in the request kwargs.
    * No course is found in database against the provided `course_id`.


@staticmethod<EOL><INDENT>def extend_course(course, enterprise_customer, request):<DEDENT>

course_run_id = course['<STR_LIT>'][<NUM_LIT:0>]['<STR_LIT:key>']<EOL>try:<EOL><INDENT>catalog_api_client = CourseCatalogApiServiceClient(enterprise_customer.site)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>LOGGER.error(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>course_run_id=course_run_id,<EOL>)<EOL>)<EOL>messages.add_generic_error_message_with_code(request, error_code)<EOL>return ({}, error_code)<EOL><DEDENT>course_details, course_run_details = catalog_api_client.get_course_and_course_run(course_run_id)<EOL>if not course_details or not course_run_details:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>LOGGER.error(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>course_run_id=course_run_id,<EOL>error_code=error_code,<EOL>)<EOL>)<EOL>messages.add_generic_error_message_with_code(request, error_code)<EOL>return ({}, error_code)<EOL><DEDENT>weeks_to_complete = course_run_details['<STR_LIT>']<EOL>course_run_image = course_run_details['<STR_LIT:image>'] or {}<EOL>course.update({<EOL>'<STR_LIT>': course_run_image.get('<STR_LIT:src>', '<STR_LIT>'),<EOL>'<STR_LIT>': course_run_details['<STR_LIT:title>'],<EOL>'<STR_LIT>': course_run_details.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>': course_run_details['<STR_LIT>'] or '<STR_LIT>',<EOL>'<STR_LIT>': clean_html_for_template_rendering(course_run_details['<STR_LIT>'] or '<STR_LIT>'),<EOL>'<STR_LIT>': course_details.get('<STR_LIT>', []),<EOL>'<STR_LIT>': course_run_details.get('<STR_LIT>', []),<EOL>'<STR_LIT>': ungettext_min_max(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>course_run_details['<STR_LIT>'] or None,<EOL>course_run_details['<STR_LIT>'] or None,<EOL>) or '<STR_LIT>',<EOL>'<STR_LIT>': ungettext(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>weeks_to_complete<EOL>).format(weeks_to_complete) if weeks_to_complete else '<STR_LIT>',<EOL>})<EOL>return course, None<EOL>

Extend a course with more details needed for the program landing page.

In particular, we add the following:

* `course_image_uri`
* `course_title`
* `course_level_type`
* `course_short_description`
* `course_full_description`
* `course_effort`
* `expected_learning_items`
* `staff`


def get_program_details(self, request, program_uuid, enterprise_customer):

try:<EOL><INDENT>course_catalog_api_client = CourseCatalogApiServiceClient(enterprise_customer.site)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>LOGGER.error(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>program_uuid=program_uuid,<EOL>)<EOL>)<EOL>messages.add_generic_error_message_with_code(request, error_code)<EOL>return ({}, error_code)<EOL><DEDENT>program_details = course_catalog_api_client.get_program_by_uuid(program_uuid)<EOL>if program_details is None:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>LOGGER.error(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>program_uuid=program_uuid,<EOL>error_code=error_code,<EOL>)<EOL>)<EOL>messages.add_generic_error_message_with_code(request, error_code)<EOL>return ({}, error_code)<EOL><DEDENT>program_type = course_catalog_api_client.get_program_type_by_slug(slugify(program_details['<STR_LIT:type>']))<EOL>if program_type is None:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>LOGGER.error(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>userid=request.user.id,<EOL>enterprise_customer=enterprise_customer.uuid,<EOL>program_uuid=program_uuid,<EOL>error_code=error_code,<EOL>)<EOL>)<EOL>messages.add_generic_error_message_with_code(request, error_code)<EOL>return ({}, error_code)<EOL><DEDENT>program_details = ProgramDataExtender(program_details, request.user).extend()<EOL>program_details['<STR_LIT>'] = False<EOL>enrollment_count = <NUM_LIT:0><EOL>for extended_course in program_details['<STR_LIT>']:<EOL><INDENT>extended_data, error_code = ProgramEnrollmentView.extend_course(<EOL>extended_course,<EOL>enterprise_customer,<EOL>request<EOL>)<EOL>if error_code:<EOL><INDENT>return ({}, error_code)<EOL><DEDENT>extended_course.update(extended_data)<EOL>extended_course_run = extended_course['<STR_LIT>'][<NUM_LIT:0>]<EOL>if extended_course_run['<STR_LIT>'] and extended_course_run['<STR_LIT>'] is None:<EOL><INDENT>program_details['<STR_LIT>'] = True<EOL>enrollment_count += <NUM_LIT:1><EOL><DEDENT><DEDENT>program_details['<STR_LIT>'] = (enrollment_count == len(program_details['<STR_LIT>']))<EOL>program_details['<STR_LIT>'] = program_type<EOL>return program_details, None<EOL>

Retrieve fundamental details used by both POST and GET versions of this view.

Specifically:

* Take the program UUID and get specific details about the program.
* Determine whether the learner is enrolled in the program.
* Determine whether the learner is certificate eligible for the program.


def get_enterprise_program_enrollment_page(self, request, enterprise_customer, program_details):

<EOL>organizations = program_details['<STR_LIT>']<EOL>organization = organizations[<NUM_LIT:0>] if organizations else {}<EOL>platform_name = get_configuration_value('<STR_LIT>', settings.PLATFORM_NAME)<EOL>program_title = program_details['<STR_LIT:title>']<EOL>program_type_details = program_details['<STR_LIT>']<EOL>program_type = program_type_details['<STR_LIT:name>']<EOL>program_courses = program_details['<STR_LIT>']<EOL>course_count = len(program_courses)<EOL>course_count_text = ungettext(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>course_count,<EOL>).format(count=course_count)<EOL>effort_info_text = ungettext_min_max(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>_('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>)<EOL>length_info_text = ungettext_min_max(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>_('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>program_details.get('<STR_LIT>'),<EOL>)<EOL>if program_details['<STR_LIT>']:<EOL><INDENT>purchase_action = _('<STR_LIT>')<EOL>item = _('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>purchase_action = _('<STR_LIT>')<EOL>item = _('<STR_LIT>')<EOL><DEDENT>program_data_sharing_consent = get_data_sharing_consent(<EOL>request.user.username,<EOL>enterprise_customer.uuid,<EOL>program_uuid=program_details['<STR_LIT>'],<EOL>)<EOL>if program_data_sharing_consent.exists and not program_data_sharing_consent.granted:<EOL><INDENT>messages.add_consent_declined_message(request, enterprise_customer, program_title)<EOL><DEDENT>discount_data = program_details.get('<STR_LIT>', {})<EOL>one_click_purchase_eligibility = program_details.get('<STR_LIT>', False)<EOL>if not one_click_purchase_eligibility:<EOL><INDENT>messages.add_unenrollable_item_message(request, '<STR_LIT>')<EOL><DEDENT>elif discount_data.get('<STR_LIT>') is None:<EOL><INDENT>messages.add_missing_price_information_message(request, program_title)<EOL><DEDENT>context_data = get_global_context(request, enterprise_customer)<EOL>context_data.update({<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _("<STR_LIT>"),<EOL>'<STR_LIT>': <NUM_LIT:2>,<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': <NUM_LIT:1>,<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>').format(<EOL>platform_name=platform_name,<EOL>program_type=program_type,<EOL>),<EOL>'<STR_LIT>': _('<STR_LIT>').format(<EOL>platform_name=platform_name<EOL>),<EOL>'<STR_LIT>': organization.get('<STR_LIT:name>'),<EOL>'<STR_LIT>': organization.get('<STR_LIT>'),<EOL>'<STR_LIT>': _('<STR_LIT>').format(organization=organization.get('<STR_LIT:name>')),<EOL>'<STR_LIT>': _('<STR_LIT>').format(item=item),<EOL>'<STR_LIT>': program_type_details['<STR_LIT>'].get('<STR_LIT>', {}).get('<STR_LIT:url>', '<STR_LIT>'),<EOL>'<STR_LIT>': program_type,<EOL>'<STR_LIT>': get_program_type_description(program_type),<EOL>'<STR_LIT>': program_title,<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': get_price_text(discount_data.get('<STR_LIT>', <NUM_LIT:0>), request),<EOL>'<STR_LIT>': get_price_text(discount_data.get('<STR_LIT>', <NUM_LIT:0>), request),<EOL>'<STR_LIT>': discount_data.get('<STR_LIT>', False),<EOL>'<STR_LIT>': program_courses,<EOL>'<STR_LIT>': [<EOL>_('<STR_LIT>'),<EOL>_('<STR_LIT>'),<EOL>],<EOL>'<STR_LIT>': _('<STR_LIT>').format(purchase_action=purchase_action),<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': program_details['<STR_LIT>'],<EOL>'<STR_LIT>': course_count_text,<EOL>'<STR_LIT>': length_info_text,<EOL>'<STR_LIT>': effort_info_text,<EOL>'<STR_LIT>': one_click_purchase_eligibility,<EOL>})<EOL>return render(request, '<STR_LIT>', context=context_data)<EOL>

Render Enterprise-specific program enrollment page.


verify_edx_resources()<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>context_data = get_global_context(request, enterprise_customer)<EOL>program_details, error_code = self.get_program_details(request, program_uuid, enterprise_customer)<EOL>if error_code:<EOL><INDENT>return render(<EOL>request,<EOL>ENTERPRISE_GENERAL_ERROR_PAGE,<EOL>context=context_data,<EOL>status=<NUM_LIT>,<EOL>)<EOL><DEDENT>if program_details['<STR_LIT>']:<EOL><INDENT>return redirect(LMS_PROGRAMS_DASHBOARD_URL.format(uuid=program_uuid))<EOL><DEDENT>course_run_ids = []<EOL>for course in program_details['<STR_LIT>']:<EOL><INDENT>for course_run in course['<STR_LIT>']:<EOL><INDENT>course_run_ids.append(course_run['<STR_LIT:key>'])<EOL><DEDENT><DEDENT>embargo_url = EmbargoApiClient.redirect_if_blocked(course_run_ids, request.user, get_ip(request), request.path)<EOL>if embargo_url:<EOL><INDENT>return redirect(embargo_url)<EOL><DEDENT>return self.get_enterprise_program_enrollment_page(request, enterprise_customer, program_details)<EOL>

Show Program Landing page for the Enterprise's Program.

Render the Enterprise's Program Enrollment page for a specific program.
The Enterprise and Program are both selected by their respective UUIDs.

Unauthenticated learners will be redirected to enterprise-linked SSO.

A 404 will be raised if any of the following conditions are met:
    * No enterprise customer UUID query parameter ``enterprise_uuid`` found in request.
    * No enterprise customer found against the enterprise customer
        uuid ``enterprise_uuid`` in the request kwargs.
    * No Program can be found given ``program_uuid`` either at all or associated with
        the Enterprise..


@method_decorator(enterprise_login_required)<EOL><INDENT>def post(self, request, enterprise_uuid, program_uuid):<DEDENT>

verify_edx_resources()<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_uuid)<EOL>with transaction.atomic():<EOL><INDENT>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL><DEDENT>context_data = get_global_context(request, enterprise_customer)<EOL>program_details, error_code = self.get_program_details(request, program_uuid, enterprise_customer)<EOL>if error_code:<EOL><INDENT>return render(<EOL>request,<EOL>ENTERPRISE_GENERAL_ERROR_PAGE,<EOL>context=context_data,<EOL>status=<NUM_LIT>,<EOL>)<EOL><DEDENT>if program_details['<STR_LIT>']:<EOL><INDENT>return redirect(LMS_PROGRAMS_DASHBOARD_URL.format(uuid=program_uuid))<EOL><DEDENT>basket_page = '<STR_LIT>'.format(<EOL>basket_url=BASKET_URL,<EOL>params=urlencode(<EOL>[tuple(['<STR_LIT>', sku]) for sku in program_details['<STR_LIT>']] +<EOL>[tuple(['<STR_LIT>', program_uuid])]<EOL>)<EOL>)<EOL>if get_data_sharing_consent(<EOL>enterprise_customer_user.username,<EOL>enterprise_customer.uuid,<EOL>program_uuid=program_uuid,<EOL>).consent_required():<EOL><INDENT>return redirect(<EOL>'<STR_LIT>'.format(<EOL>grant_data_sharing_url=reverse('<STR_LIT>'),<EOL>params=urlencode(<EOL>{<EOL>'<STR_LIT>': basket_page,<EOL>'<STR_LIT>': reverse(<EOL>'<STR_LIT>',<EOL>args=[enterprise_customer.uuid, program_uuid]<EOL>),<EOL>'<STR_LIT>': enterprise_customer.uuid,<EOL>'<STR_LIT>': program_uuid,<EOL>}<EOL>)<EOL>)<EOL>)<EOL><DEDENT>return redirect(basket_page)<EOL>


enterprise_customer_uuid = kwargs.get('<STR_LIT>', '<STR_LIT>')<EOL>course_run_id = kwargs.get('<STR_LIT>', '<STR_LIT>')<EOL>course_key = kwargs.get('<STR_LIT>', '<STR_LIT>')<EOL>program_uuid = kwargs.get('<STR_LIT>', '<STR_LIT>')<EOL>return enterprise_customer_uuid, course_run_id, course_key, program_uuid<EOL>

Get the base variables for any view to route to.

Currently gets:
- `enterprise_uuid` - the UUID of the enterprise customer.
- `course_run_id` - the ID of the course, if applicable.
- `program_uuid` - the UUID of the program, if applicable.


@staticmethod<EOL><INDENT>def get_course_run_id(user, enterprise_customer, course_key):<DEDENT>

try:<EOL><INDENT>course = CourseCatalogApiServiceClient(enterprise_customer.site).get_course_details(course_key)<EOL><DEDENT>except ImproperlyConfigured:<EOL><INDENT>raise Http404<EOL><DEDENT>users_all_enrolled_courses = EnrollmentApiClient().get_enrolled_courses(user.username)<EOL>users_active_course_runs = get_active_course_runs(<EOL>course,<EOL>users_all_enrolled_courses<EOL>) if users_all_enrolled_courses else []<EOL>course_run = get_current_course_run(course, users_active_course_runs)<EOL>if course_run:<EOL><INDENT>course_run_id = course_run['<STR_LIT:key>']<EOL>return course_run_id<EOL><DEDENT>else:<EOL><INDENT>raise Http404<EOL><DEDENT>

User is requesting a course, we need to translate that into the current course run.

:param user:
:param enterprise_customer:
:param course_key:
:return: course_run_id


def eligible_for_direct_audit_enrollment(self, request, enterprise_customer, resource_id, course_key=None):

course_identifier = course_key if course_key else resource_id<EOL>return request.GET.get('<STR_LIT>') andrequest.path == self.COURSE_ENROLLMENT_VIEW_URL.format(enterprise_customer.uuid, course_identifier) andenterprise_customer.catalog_contains_course(resource_id) andEnrollmentApiClient().has_course_mode(resource_id, '<STR_LIT>')<EOL>

Return whether a request is eligible for direct audit enrollment for a particular enterprise customer.

'resource_id' can be either course_run_id or program_uuid.
We check for the following criteria:
- The `audit` query parameter.
- The user's being routed to the course enrollment landing page.
- The customer's catalog contains the course in question.
- The audit track is an available mode for the course.


def redirect(self, request, *args, **kwargs):

enterprise_customer_uuid, course_run_id, course_key, program_uuid = RouterView.get_path_variables(**kwargs)<EOL>resource_id = course_key or course_run_id or program_uuid<EOL>path = re.sub('<STR_LIT>'.format(enterprise_customer_uuid, re.escape(resource_id)), '<STR_LIT:{}>', request.path)<EOL>kwargs.pop('<STR_LIT>', None)<EOL>return self.VIEWS[path].as_view()(request, *args, **kwargs)<EOL>

Redirects to the appropriate view depending on where the user came from.


@method_decorator(enterprise_login_required)<EOL><INDENT>@method_decorator(force_fresh_session)<EOL>def get(self, request, *args, **kwargs):<DEDENT>

enterprise_customer_uuid, course_run_id, course_key, program_uuid = RouterView.get_path_variables(**kwargs)<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_customer_uuid)<EOL>if course_key:<EOL><INDENT>try:<EOL><INDENT>course_run_id = RouterView.get_course_run_id(request.user, enterprise_customer, course_key)<EOL><DEDENT>except Http404:<EOL><INDENT>context_data = get_global_context(request, enterprise_customer)<EOL>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_key=course_key,<EOL>course_run_id=course_run_id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>program_uuid=program_uuid,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT>kwargs['<STR_LIT>'] = course_run_id<EOL><DEDENT>with transaction.atomic():<EOL><INDENT>enterprise_customer_user, __ = EnterpriseCustomerUser.objects.get_or_create(<EOL>enterprise_customer=enterprise_customer,<EOL>user_id=request.user.id<EOL>)<EOL>enterprise_customer_user.update_session(request)<EOL><DEDENT>resource_id = course_run_id or program_uuid<EOL>if self.eligible_for_direct_audit_enrollment(request, enterprise_customer, resource_id, course_key):<EOL><INDENT>try:<EOL><INDENT>enterprise_customer_user.enroll(resource_id, '<STR_LIT>', cohort=request.GET.get('<STR_LIT>', None))<EOL>track_enrollment('<STR_LIT>', request.user.id, resource_id, request.get_full_path())<EOL><DEDENT>except (CourseEnrollmentDowngradeError, CourseEnrollmentPermissionError):<EOL><INDENT>pass<EOL><DEDENT>return redirect(LMS_COURSEWARE_URL.format(course_id=resource_id))<EOL><DEDENT>return self.redirect(request, *args, **kwargs)<EOL>

Run some custom GET logic for Enterprise workflows before routing the user through existing views.

In particular, before routing to existing views:
- If the requested resource is a course, find the current course run for that course,
  and make that course run the requested resource instead.
- Look to see whether a request is eligible for direct audit enrollment, and if so, directly enroll the user.


@method_decorator(enterprise_login_required)<EOL><INDENT>def post(self, request, *args, **kwargs):<DEDENT>

<EOL>enterprise_customer_uuid, course_run_id, course_key, program_uuid = RouterView.get_path_variables(**kwargs)<EOL>enterprise_customer = get_enterprise_customer_or_404(enterprise_customer_uuid)<EOL>if course_key:<EOL><INDENT>context_data = get_global_context(request, enterprise_customer)<EOL>try:<EOL><INDENT>kwargs['<STR_LIT>'] = RouterView.get_course_run_id(request.user, enterprise_customer, course_key)<EOL><DEDENT>except Http404:<EOL><INDENT>error_code = '<STR_LIT>'<EOL>log_message = (<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>course_key=course_key,<EOL>course_run_id=course_run_id,<EOL>enterprise_customer_uuid=enterprise_customer_uuid,<EOL>error_code=error_code,<EOL>userid=request.user.id,<EOL>program_uuid=program_uuid,<EOL>)<EOL>)<EOL>return render_page_with_error_code_message(request, context_data, error_code, log_message)<EOL><DEDENT><DEDENT>return self.redirect(request, *args, **kwargs)<EOL>

Run some custom POST logic for Enterprise workflows before routing the user through existing views.


return json.dumps(COURSE_MODE_SORT_ORDER)<EOL>


def add_consent_declined_message(request, enterprise_customer, item):

Add a message to the Django messages store indicating that the user has declined data sharing consent.

Arguments:
    request (HttpRequest): The current request.
    enterprise_customer (EnterpriseCustomer): The EnterpriseCustomer associated with this request.
    item (str): A string containing information about the item for which consent was declined.


Add a message to the Django messages store indicating that we failed to retrieve price information about an item.

:param request: The current request.
:param item: The item for which price information is missing. Example: a program title, or a course.


Add a message to the Django message store indicating that the item (i.e. course run, program) is unenrollable.

:param request: The current request.
:param item: The item that is unenrollable (i.e. a course run).


Add message to request indicating that there was an issue processing request.

Arguments:
    request: The current request.


Add message to request indicating that there was an issue processing request.

Arguments:
    request: The current request.
    error_code: A string error code to be used to point devs to the spot in
                the code where this error occurred.


def get(self, request, template_id, view_type):

template = get_object_or_404(EnrollmentNotificationEmailTemplate, pk=template_id)<EOL>if view_type not in self.view_type_contexts:<EOL><INDENT>return HttpResponse(status=<NUM_LIT>)<EOL><DEDENT>base_context = self.view_type_contexts[view_type].copy()<EOL>base_context.update({'<STR_LIT>': self.get_user_name(request)})<EOL>return HttpResponse(template.render_html_template(base_context), content_type='<STR_LIT>')<EOL>

Render the given template with the stock data.


return request.user.first_name or request.user.username<EOL>


opts = customer._meta<EOL>codename = get_permission_codename('<STR_LIT>', opts)<EOL>has_change_permission = request.user.has_perm('<STR_LIT>' % (opts.app_label, codename))<EOL>return {<EOL>'<STR_LIT>': has_change_permission,<EOL>'<STR_LIT>': opts<EOL>}<EOL>


def _build_context(self, request, enterprise_customer_uuid):

enterprise_customer = EnterpriseCustomer.objects.get(uuid=enterprise_customer_uuid)  <EOL>context = {<EOL>self.ContextParameters.ENTERPRISE_CUSTOMER: enterprise_customer,<EOL>}<EOL>context.update(admin.site.each_context(request))<EOL>context.update(self._build_admin_context(request, enterprise_customer))<EOL>return context<EOL>

Build common context parts used by different handlers in this view.


def get(self, request, enterprise_customer_uuid):

context = self._build_context(request, enterprise_customer_uuid)<EOL>transmit_courses_metadata_form = TransmitEnterpriseCoursesForm()<EOL>context.update({self.ContextParameters.TRANSMIT_COURSES_METADATA_FORM: transmit_courses_metadata_form})<EOL>return render(request, self.template, context)<EOL>

Handle GET request - render "Transmit courses metadata" form.

Arguments:
    request (django.http.request.HttpRequest): Request instance
    enterprise_customer_uuid (str): Enterprise Customer UUID

Returns:
    django.http.response.HttpResponse: HttpResponse


def post(self, request, enterprise_customer_uuid):

transmit_courses_metadata_form = TransmitEnterpriseCoursesForm(request.POST)<EOL>if transmit_courses_metadata_form.is_valid():<EOL><INDENT>channel_worker_username = transmit_courses_metadata_form.cleaned_data['<STR_LIT>']<EOL>call_command(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>', channel_worker_username,<EOL>enterprise_customer=enterprise_customer_uuid<EOL>)<EOL>return HttpResponseRedirect('<STR_LIT>')<EOL><DEDENT>context = self._build_context(request, enterprise_customer_uuid)<EOL>context.update({self.ContextParameters.TRANSMIT_COURSES_METADATA_FORM: transmit_courses_metadata_form})<EOL>return render(request, self.template, context)<EOL>

Handle POST request - handle form submissions.

Arguments:
    request (django.http.request.HttpRequest): Request instance
    enterprise_customer_uuid (str): Enterprise Customer UUID


opts = customer._meta<EOL>codename = get_permission_codename("<STR_LIT>", opts)<EOL>has_change_permission = request.user.has_perm("<STR_LIT>" % (opts.app_label, codename))<EOL>return {<EOL>"<STR_LIT>": has_change_permission,<EOL>"<STR_LIT>": opts<EOL>}<EOL>


def _build_context(self, request, customer_uuid):

<EOL>enterprise_customer = EnterpriseCustomer.objects.get(uuid=customer_uuid)  <EOL>search_keyword = self.get_search_keyword(request)<EOL>linked_learners = self.get_enterprise_customer_user_queryset(request, search_keyword, customer_uuid)<EOL>pending_linked_learners = self.get_pending_users_queryset(search_keyword, customer_uuid)<EOL>context = {<EOL>self.ContextParameters.ENTERPRISE_CUSTOMER: enterprise_customer,<EOL>self.ContextParameters.PENDING_LEARNERS: pending_linked_learners,<EOL>self.ContextParameters.LEARNERS: linked_learners,<EOL>self.ContextParameters.SEARCH_KEYWORD: search_keyword or '<STR_LIT>',<EOL>self.ContextParameters.ENROLLMENT_URL: settings.LMS_ENROLLMENT_API_PATH,<EOL>}<EOL>context.update(admin.site.each_context(request))<EOL>context.update(self._build_admin_context(request, enterprise_customer))<EOL>return context<EOL>


return request.GET.get('<STR_LIT:q>', None)<EOL>

Retrieve the search querystring from the GET parameters.


def get_enterprise_customer_user_queryset(self, request, search_keyword, customer_uuid, page_size=PAGE_SIZE):

page = request.GET.get('<STR_LIT>', <NUM_LIT:1>)<EOL>learners = EnterpriseCustomerUser.objects.filter(enterprise_customer__uuid=customer_uuid)<EOL>user_ids = learners.values_list('<STR_LIT>', flat=True)<EOL>matching_users = User.objects.filter(pk__in=user_ids)<EOL>if search_keyword is not None:<EOL><INDENT>matching_users = matching_users.filter(<EOL>Q(email__icontains=search_keyword) | Q(username__icontains=search_keyword)<EOL>)<EOL><DEDENT>matching_user_ids = matching_users.values_list('<STR_LIT>', flat=True)<EOL>learners = learners.filter(user_id__in=matching_user_ids)<EOL>return paginated_list(learners, page, page_size)<EOL>

Get the list of EnterpriseCustomerUsers we want to render.

Arguments:
    request (HttpRequest): HTTP Request instance.
    search_keyword (str): The keyword to search for in users' email addresses and usernames.
    customer_uuid (str): A unique identifier to filter down to only users linked to a
    particular EnterpriseCustomer.
    page_size (int): Number of learners displayed in each paginated set.


def get_pending_users_queryset(self, search_keyword, customer_uuid):

queryset = PendingEnterpriseCustomerUser.objects.filter(<EOL>enterprise_customer__uuid=customer_uuid<EOL>)<EOL>if search_keyword is not None:<EOL><INDENT>queryset = queryset.filter(user_email__icontains=search_keyword)<EOL><DEDENT>return queryset<EOL>

Get the list of PendingEnterpriseCustomerUsers we want to render.

Args:
    search_keyword (str): The keyword to search for in pending users' email addresses.
    customer_uuid (str): A unique identifier to filter down to only pending users
    linked to a particular EnterpriseCustomer.


@classmethod<EOL><INDENT>def _handle_singular(cls, enterprise_customer, manage_learners_form):<DEDENT>

form_field_value = manage_learners_form.cleaned_data[ManageLearnersForm.Fields.EMAIL_OR_USERNAME]<EOL>email = email_or_username__to__email(form_field_value)<EOL>try:<EOL><INDENT>validate_email_to_link(email, form_field_value, ValidationMessages.INVALID_EMAIL_OR_USERNAME, True)<EOL><DEDENT>except ValidationError as exc:<EOL><INDENT>manage_learners_form.add_error(ManageLearnersForm.Fields.EMAIL_OR_USERNAME, exc)<EOL><DEDENT>else:<EOL><INDENT>EnterpriseCustomerUser.objects.link_user(enterprise_customer, email)<EOL>return [email]<EOL><DEDENT>

Link single user by email or username.

Arguments:
    enterprise_customer (EnterpriseCustomer): learners will be linked to this Enterprise Customer instance
    manage_learners_form (ManageLearnersForm): bound ManageLearners form instance


@classmethod<EOL><INDENT>def _handle_bulk_upload(cls, enterprise_customer, manage_learners_form, request, email_list=None):<DEDENT>

errors = []<EOL>emails = set()<EOL>already_linked_emails = []<EOL>duplicate_emails = []<EOL>csv_file = manage_learners_form.cleaned_data[ManageLearnersForm.Fields.BULK_UPLOAD]<EOL>if email_list:<EOL><INDENT>parsed_csv = [{ManageLearnersForm.CsvColumns.EMAIL: email} for email in email_list]<EOL><DEDENT>else:<EOL><INDENT>parsed_csv = parse_csv(csv_file, expected_columns={ManageLearnersForm.CsvColumns.EMAIL})<EOL><DEDENT>try:<EOL><INDENT>for index, row in enumerate(parsed_csv):<EOL><INDENT>email = row[ManageLearnersForm.CsvColumns.EMAIL]<EOL>try:<EOL><INDENT>already_linked = validate_email_to_link(email, ignore_existing=True)<EOL><DEDENT>except ValidationError as exc:<EOL><INDENT>message = _("<STR_LIT>").format(line=index + <NUM_LIT:1>, message=exc)<EOL>errors.append(message)<EOL><DEDENT>else:<EOL><INDENT>if already_linked:<EOL><INDENT>already_linked_emails.append((email, already_linked.enterprise_customer))<EOL><DEDENT>elif email in emails:<EOL><INDENT>duplicate_emails.append(email)<EOL><DEDENT>else:<EOL><INDENT>emails.add(email)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>except ValidationError as exc:<EOL><INDENT>errors.append(exc)<EOL><DEDENT>if errors:<EOL><INDENT>manage_learners_form.add_error(<EOL>ManageLearnersForm.Fields.GENERAL_ERRORS, ValidationMessages.BULK_LINK_FAILED<EOL>)<EOL>for error in errors:<EOL><INDENT>manage_learners_form.add_error(ManageLearnersForm.Fields.BULK_UPLOAD, error)<EOL><DEDENT>return<EOL><DEDENT>for email in emails:<EOL><INDENT>EnterpriseCustomerUser.objects.link_user(enterprise_customer, email)<EOL><DEDENT>count = len(emails)<EOL>messages.success(request, ungettext(<EOL>"<STR_LIT>",<EOL>"<STR_LIT>",<EOL>count<EOL>).format(count=count, enterprise_customer_name=enterprise_customer.name))<EOL>this_customer_linked_emails = [<EOL>email for email, customer in already_linked_emails if customer == enterprise_customer<EOL>]<EOL>other_customer_linked_emails = [<EOL>email for email, __ in already_linked_emails if email not in this_customer_linked_emails<EOL>]<EOL>if this_customer_linked_emails:<EOL><INDENT>messages.warning(<EOL>request,<EOL>_(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(<EOL>list_of_emails="<STR_LIT:U+002CU+0020>".join(this_customer_linked_emails)<EOL>)<EOL>)<EOL><DEDENT>if other_customer_linked_emails:<EOL><INDENT>messages.warning(<EOL>request,<EOL>_(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(<EOL>enterprise_customer_name=enterprise_customer.name,<EOL>list_of_emails="<STR_LIT:U+002CU+0020>".join(other_customer_linked_emails),<EOL>)<EOL>)<EOL><DEDENT>if duplicate_emails:<EOL><INDENT>messages.warning(<EOL>request,<EOL>_(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(<EOL>list_of_emails="<STR_LIT:U+002CU+0020>".join(duplicate_emails)<EOL>)<EOL>)<EOL><DEDENT>all_processable_emails = list(emails) + this_customer_linked_emails<EOL>return all_processable_emails<EOL>

Bulk link users by email.

Arguments:
    enterprise_customer (EnterpriseCustomer): learners will be linked to this Enterprise Customer instance
    manage_learners_form (ManageLearnersForm): bound ManageLearners form instance
    request (django.http.request.HttpRequest): HTTP Request instance
    email_list (iterable): A list of pre-processed email addresses to handle using the form