<commit_before><?php
/**
 * Handles redirecting and tracking links in newsletters.
 *
 * @package silverstripe-newsletter-tracking
 */
class NewsletterLinkController extends Controller {

	public static $url_handlers = array(
		'$User!/$Hash!' => 'handleUserLink',
		'$Hash!'        => 'handleLink'
	);

	public static $allowed_actions = array(
		'handleLink',
		'handleUserLink'
	);

	protected $link;

	public function index() {
		$this->httpError(404);
	}

	/**
	 * Handles redirecting and tracking newsletter links without a user hash.
	 */
	public function handleLink($request) {
		$this->link = DataObject::get_one('Newsletter_TrackedLink', sprintf(
			'"Hash" = \'%s\'', Convert::raw2sql($request->param('Hash'))
		));

		if (!$this->link) {
			$this->httpError(404);
		}

		if (!Cookie::get("NewsletterLink-{$this->link->Hash}")) {
			$this->link->Visits++;
			$this->link->write();

			Cookie::set("NewsletterLink-{$this->link->Hash}", true);
		}

		return $this->redirect($this->link->Original, 301);
	}

	/**
	 * Handles redirecting and tracking newsletter links with a token also
	 * identifying the user.
	 *
	 * @uses NewsletterLinkController::handleLink
	 */
	public function handleUserLink($request) {
		$response = $this->handleLink($request);

		$user = DataObject::get_one('Member', sprintf(
			'"NewsletterTrackingToken" = \'%s\'', Convert::raw2sql($request->param('User'))
		));

		if ($user) {
			$this->link->ViewedMembers()->add($user);
		}

		return $response;
	}

}<commit_msg>Mark a user as having viewed the newsletter when they click a link.<commit_after><?php
/**
 * Handles redirecting and tracking links in newsletters.
 *
 * @package silverstripe-newsletter-tracking
 */
class NewsletterLinkController extends Controller {

	public static $url_handlers = array(
		'$User!/$Hash!' => 'handleUserLink',
		'$Hash!'        => 'handleLink'
	);

	public static $allowed_actions = array(
		'handleLink',
		'handleUserLink'
	);

	protected $link;

	public function index() {
		$this->httpError(404);
	}

	/**
	 * Handles redirecting and tracking newsletter links without a user hash.
	 */
	public function handleLink($request) {
		$this->link = DataObject::get_one('Newsletter_TrackedLink', sprintf(
			'"Hash" = \'%s\'', Convert::raw2sql($request->param('Hash'))
		));

		if (!$this->link) {
			$this->httpError(404);
		}

		if (!Cookie::get("NewsletterLink-{$this->link->Hash}")) {
			$this->link->Visits++;
			$this->link->write();

			Cookie::set("NewsletterLink-{$this->link->Hash}", true);
		}

		return $this->redirect($this->link->Original, 301);
	}

	/**
	 * Handles redirecting and tracking newsletter links with a token also
	 * identifying the user.
	 *
	 * @uses NewsletterLinkController::handleLink
	 */
	public function handleUserLink($request) {
		$response = $this->handleLink($request);

		$user = DataObject::get_one('Member', sprintf(
			'"NewsletterTrackingToken" = \'%s\'', Convert::raw2sql($request->param('User'))
		));

		if ($user) {
			$this->link->Newsletter()->ViewedMembers()->add($user);
			$this->link->ViewedMembers()->add($user);
		}

		return $response;
	}

}
{'fraction_non_alphanumeric': 0.18018595703751203, 'fraction_numerical': 0.007053542802180186, 'mean_word_length': 4.288135593220339, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4033345', 'n_tokens_mistral': 1102, 'n_tokens_neox': 973, 'n_words': 205}