diff --git a/ietf/meeting/migrations/0031_auto_20200803_1153.py b/ietf/meeting/migrations/0031_auto_20200803_1153.py
new file mode 100644
index 000000000..8a5ac54aa
--- /dev/null
+++ b/ietf/meeting/migrations/0031_auto_20200803_1153.py
@@ -0,0 +1,22 @@
+# Generated by Django 2.2.14 on 2020-08-03 11:53
+
+from django.db import migrations
+import django.db.models.deletion
+import ietf.utils.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('name', '0018_slidesubmissionstatusname'),
+        ('doc', '0035_populate_docextresources'),
+        ('meeting', '0030_allow_empty_joint_with_sessions'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='slidesubmission',
+            name='doc',
+            field=ietf.utils.models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='doc.Document'),
+        ),
+    ]
diff --git a/ietf/meeting/migrations/0032_auto_20200824_1642.py b/ietf/meeting/migrations/0032_auto_20200824_1642.py
new file mode 100644
index 000000000..31155da6a
--- /dev/null
+++ b/ietf/meeting/migrations/0032_auto_20200824_1642.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.2.14 on 2020-08-03 11:53
+
+from django.db import migrations
+import django.db.models.deletion
+import ietf.utils.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('meeting', '0031_auto_20200803_1153'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='slidesubmission',
+            name='status',
+            field=ietf.utils.models.ForeignKey(null=True, default='pending', on_delete=django.db.models.deletion.SET_NULL, to='name.SlideSubmissionStatusName'),
+        ),
+    ]
diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index 5df942106..c73374d34 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -29,7 +29,7 @@ from ietf.dbtemplate.models import DBTemplate
 from ietf.doc.models import Document
 from ietf.group.models import Group
 from ietf.group.utils import can_manage_materials
-from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName, ImportantDateName, TimerangeName
+from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName, ImportantDateName, TimerangeName, SlideSubmissionStatusName
 from ietf.person.models import Person
 from ietf.utils.decorators import memoize
 from ietf.utils.storage import NoLocationMigrationFileSystemStorage
@@ -1277,6 +1277,8 @@ class SlideSubmission(models.Model):
     filename = models.CharField(max_length=255)
     apply_to_all = models.BooleanField(default=False)
     submitter = ForeignKey(Person)
+    status      = ForeignKey(SlideSubmissionStatusName, null=True, default='pending', on_delete=models.SET_NULL)
+    doc         = ForeignKey(Document, null=True, on_delete=models.SET_NULL)
 
     def staged_filepath(self):
         return os.path.join(settings.SLIDE_STAGING_PATH , self.filename)
diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py
index b3dcf9094..30889de0b 100644
--- a/ietf/meeting/tests_views.py
+++ b/ietf/meeting/tests_views.py
@@ -2788,6 +2788,7 @@ class MaterialsTests(TestCase):
     def test_disapprove_proposed_slides(self):
         submission = SlideSubmissionFactory()
         submission.session.meeting.importantdate_set.create(name_id='revsub',date=datetime.date.today()+datetime.timedelta(days=20))
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 1)
         chair = RoleFactory(group=submission.session.group,name_id='chair').person
         url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
         login_testing_unauthorized(self, chair.user.username, url)
@@ -2795,7 +2796,11 @@ class MaterialsTests(TestCase):
         self.assertEqual(r.status_code,200)
         r = self.client.post(url,dict(title='some title',disapprove="disapprove"))
         self.assertEqual(r.status_code,302)
-        self.assertEqual(SlideSubmission.objects.count(), 0)
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'rejected').count(), 1)
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 0)
+        r = self.client.get(url)
+        self.assertEqual(r.status_code, 200)
+        self.assertContains(r, "These slides have already been  rejected")
 
     def test_approve_proposed_slides(self):
         submission = SlideSubmissionFactory()
@@ -2804,13 +2809,22 @@ class MaterialsTests(TestCase):
         chair = RoleFactory(group=submission.session.group,name_id='chair').person
         url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':submission.pk,'num':submission.session.meeting.number})
         login_testing_unauthorized(self, chair.user.username, url)
+        self.assertEqual(submission.status_id, 'pending')
+        self.assertIsNone(submission.doc)
         r = self.client.get(url)
         self.assertEqual(r.status_code,200)
         r = self.client.post(url,dict(title='different title',approve='approve'))
         self.assertEqual(r.status_code,302)
-        self.assertEqual(SlideSubmission.objects.count(), 0)
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(), 0)
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'approved').count(), 1)
+        submission = SlideSubmission.objects.get(id = submission.id)
+        self.assertEqual(submission.status_id, 'approved')
+        self.assertIsNotNone(submission.doc)
         self.assertEqual(session.sessionpresentation_set.count(),1)
         self.assertEqual(session.sessionpresentation_set.first().document.title,'different title')
+        r = self.client.get(url)
+        self.assertEqual(r.status_code, 200)
+        self.assertContains(r, "These slides have already been  approved")
 
     def test_approve_proposed_slides_multisession_apply_one(self):
         submission = SlideSubmissionFactory(session__meeting__type_id='ietf')
@@ -2881,7 +2895,7 @@ class MaterialsTests(TestCase):
         self.assertEqual(r.status_code, 302)
         self.client.logout()       
 
-        (first_submission, second_submission) = SlideSubmission.objects.filter(session=session).order_by('id')
+        (first_submission, second_submission) = SlideSubmission.objects.filter(session=session, status__slug = 'pending').order_by('id')
 
         approve_url = urlreverse('ietf.meeting.views.approve_proposed_slides', kwargs={'slidesubmission_id':second_submission.pk,'num':second_submission.session.meeting.number})
         login_testing_unauthorized(self, chair.user.username, approve_url)
@@ -2893,7 +2907,8 @@ class MaterialsTests(TestCase):
         self.assertEqual(r.status_code,302)
         self.client.logout()
 
-        self.assertEqual(SlideSubmission.objects.count(),0)
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'pending').count(),0)
+        self.assertEqual(SlideSubmission.objects.filter(status__slug = 'rejected').count(),1)
         self.assertEqual(session.sessionpresentation_set.first().document.rev,'01')
         path = os.path.join(submission.session.meeting.get_materials_path(),'slides')
         filename = os.path.join(path,session.sessionpresentation_set.first().document.name+'-01.txt')
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 4008d9cc9..b8a847207 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -25,7 +25,7 @@ from wsgiref.handlers import format_date_time
 
 from django import forms
 from django.shortcuts import render, redirect, get_object_or_404
-from django.http import HttpResponse, HttpResponseRedirect, Http404
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, Http404
 from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth.decorators import login_required
@@ -79,6 +79,7 @@ from ietf.meeting.utils import current_session_status
 from ietf.meeting.utils import data_for_meetings_overview
 from ietf.meeting.utils import preprocess_constraints_for_meeting_schedule_editor
 from ietf.message.utils import infer_message
+from ietf.name.models import SlideSubmissionStatusName
 from ietf.secr.proceedings.utils import handle_upload_file
 from ietf.secr.proceedings.proc_utils import (get_progress_stats, post_process, import_audio_files,
     create_recording)
@@ -1541,9 +1542,9 @@ def session_details(request, num, acronym):
     pending_suggestions = None
     if request.user.is_authenticated:
         if can_manage:
-            pending_suggestions = session.slidesubmission_set.all()
+            pending_suggestions = session.slidesubmission_set.filter(status__slug='pending')
         else:
-            pending_suggestions = session.slidesubmission_set.filter(submitter=request.user.person)
+            pending_suggestions = session.slidesubmission_set.filter(status__slug='pending', submitter=request.user.person)
 
     return render(request, "meeting/session_details.html",
                   { 'scheduled_sessions':scheduled_sessions ,
@@ -3146,13 +3147,16 @@ def approve_proposed_slides(request, slidesubmission_id, num):
     name, _ = os.path.splitext(submission.filename)
     name = name[:name.rfind('-ss')]
     existing_doc = Document.objects.filter(name=name).first()
-    if request.method == 'POST':
+    if request.method == 'POST' and submission.status.slug == 'pending':
         form = ApproveSlidesForm(show_apply_to_all_checkbox, request.POST)
         if form.is_valid():
             apply_to_all = submission.session.type_id == 'regular'
             if show_apply_to_all_checkbox:
                 apply_to_all = form.cleaned_data['apply_to_all']
             if request.POST.get('approve'):
+                # Ensure that we have a file to approve.  The system gets cranky otherwise.
+                if submission.filename is None or submission.filename == '' or not os.path.isfile(submission.staged_filepath()):
+                    return HttpResponseNotFound("The slides you attempted to approve could not be found.  Please disapprove and delete them instead.")
                 title = form.cleaned_data['title']
                 if existing_doc:
                    doc = Document.objects.get(name=name)
@@ -3192,15 +3196,29 @@ def approve_proposed_slides(request, slidesubmission_id, num):
                 os.rename(submission.staged_filepath(), os.path.join(path, target_filename))
                 post_process(doc)
                 acronym = submission.session.group.acronym
-                submission.delete()
+                submission.status = SlideSubmissionStatusName.objects.get(slug='approved')
+                submission.doc = doc
+                submission.save()
                 return redirect('ietf.meeting.views.session_details',num=num,acronym=acronym)
             elif request.POST.get('disapprove'):
-                os.unlink(submission.staged_filepath())
+                # Errors in processing a submit request sometimes result
+                # in a SlideSubmission object without a file.  Handle
+                # this case and keep processing the 'disapprove' even if
+                # the filename doesn't exist.
+                try:
+                    if submission.filename != None and submission.filename != '':
+                        os.unlink(submission.staged_filepath())
+                except (FileNotFoundError, IsADirectoryError):
+                    pass
                 acronym = submission.session.group.acronym
-                submission.delete()
+                submission.status = SlideSubmissionStatusName.objects.get(slug='rejected')
+                submission.save()
                 return redirect('ietf.meeting.views.session_details',num=num,acronym=acronym)
             else:
                 pass
+    elif not submission.status.slug == 'pending':
+        return render(request, "meeting/previously_approved_slides.html",
+                      {'submission': submission })
     else:
         initial = {
             'title': submission.title,
diff --git a/ietf/name/admin.py b/ietf/name/admin.py
index 8462bddeb..81182f79a 100644
--- a/ietf/name/admin.py
+++ b/ietf/name/admin.py
@@ -11,7 +11,7 @@ from ietf.name.models import (
     ReviewRequestStateName, ReviewResultName, ReviewTypeName, RoleName, RoomResourceName,
     SessionStatusName, StdLevelName, StreamName, TimeSlotTypeName, TopicAudienceName,
     DocUrlTagName, ReviewAssignmentStateName, ReviewerQueuePolicyName, TimerangeName,
-    ExtResourceName, ExtResourceTypeName, )
+    ExtResourceName, ExtResourceTypeName, SlideSubmissionStatusName)
 
 
 from ietf.stats.models import CountryAlias
@@ -89,3 +89,4 @@ admin.site.register(TimerangeName, NameAdmin)
 admin.site.register(TopicAudienceName, NameAdmin)
 admin.site.register(DocUrlTagName, NameAdmin)
 admin.site.register(ExtResourceTypeName, NameAdmin)
+admin.site.register(SlideSubmissionStatusName, NameAdmin)
diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json
index 21253571c..2fe5a4c5d 100644
--- a/ietf/name/fixtures/names.json
+++ b/ietf/name/fixtures/names.json
@@ -12077,6 +12077,36 @@
     "model": "name.sessionstatusname",
     "pk": "schedw"
   },
+  {
+    "fields": {
+      "desc": "Approved",
+      "name": "approved",
+      "order": 1,
+      "used": true
+    },
+    "model": "name.slidesubmissionstatusname",
+    "pk": "approved"
+  },
+  {
+    "fields": {
+      "desc": "Pending",
+      "name": "pending",
+      "order": 0,
+      "used": true
+    },
+    "model": "name.slidesubmissionstatusname",
+    "pk": "pending"
+  },
+  {
+    "fields": {
+      "desc": "Rejected",
+      "name": "rejected",
+      "order": 2,
+      "used": true
+    },
+    "model": "name.slidesubmissionstatusname",
+    "pk": "rejected"
+  },
   {
     "fields": {
       "desc": "",
@@ -14905,7 +14935,7 @@
     "fields": {
       "command": "xym",
       "switch": "--version",
-      "time": "2020-08-12T00:12:54.984",
+      "time": "2020-07-23T00:12:27.508",
       "used": true,
       "version": "xym 0.4.8"
     },
@@ -14916,7 +14946,7 @@
     "fields": {
       "command": "pyang",
       "switch": "--version",
-      "time": "2020-08-12T00:12:56.359",
+      "time": "2020-07-23T00:12:28.886",
       "used": true,
       "version": "pyang 2.3.2"
     },
@@ -14927,7 +14957,7 @@
     "fields": {
       "command": "yanglint",
       "switch": "--version",
-      "time": "2020-08-12T00:12:56.632",
+      "time": "2020-07-23T00:12:29.140",
       "used": true,
       "version": "yanglint SO 1.6.7"
     },
@@ -14938,7 +14968,7 @@
     "fields": {
       "command": "xml2rfc",
       "switch": "--version",
-      "time": "2020-08-12T00:12:58.366",
+      "time": "2020-07-23T00:12:30.892",
       "used": true,
       "version": "xml2rfc 2.47.0"
     },
diff --git a/ietf/name/migrations/0018_slidesubmissionstatusname.py b/ietf/name/migrations/0018_slidesubmissionstatusname.py
new file mode 100644
index 000000000..b0f1e18e4
--- /dev/null
+++ b/ietf/name/migrations/0018_slidesubmissionstatusname.py
@@ -0,0 +1,42 @@
+# Generated by Django 2.2.14 on 2020-08-03 11:53
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('name', '0017_update_constraintname_order_and_label'),
+    ]
+
+    def forward(apps, schema_editor):
+        SlideSubmissionStatusName = apps.get_model('name', 'SlideSubmissionStatusName')
+        slide_submission_status_names = [
+            ('pending', 'Pending'),
+            ('approved', 'Approved'),
+            ('rejected', 'Rejected'),
+        ]
+        for order, (slug, desc) in enumerate(slide_submission_status_names):
+            SlideSubmissionStatusName.objects.create(slug=slug, name=slug, desc=desc, used=True, order=order)
+
+
+    def reverse(apps, schema_editor):
+        pass
+
+    operations = [
+        migrations.CreateModel(
+            name='SlideSubmissionStatusName',
+            fields=[
+                ('slug', models.CharField(max_length=32, primary_key=True, serialize=False)),
+                ('name', models.CharField(max_length=255)),
+                ('desc', models.TextField(blank=True)),
+                ('used', models.BooleanField(default=True)),
+                ('order', models.IntegerField(default=0)),
+            ],
+            options={
+                'ordering': ['order', 'name'],
+                'abstract': False,
+            },
+        ),
+        migrations.RunPython(forward, reverse),
+    ]
diff --git a/ietf/name/models.py b/ietf/name/models.py
index 648f07abd..a1d2deebf 100644
--- a/ietf/name/models.py
+++ b/ietf/name/models.py
@@ -130,3 +130,5 @@ class ExtResourceTypeName(NameModel):
 class ExtResourceName(NameModel):
     """GitHub Repository URL, GitHub Username, ..."""
     type = ForeignKey(ExtResourceTypeName)
+class SlideSubmissionStatusName(NameModel):
+    "Pending, Accepted, Rejected"
diff --git a/ietf/name/resources.py b/ietf/name/resources.py
index 80c78842a..40d2cc076 100644
--- a/ietf/name/resources.py
+++ b/ietf/name/resources.py
@@ -17,7 +17,8 @@ from ietf.name.models import ( AgendaTypeName, BallotPositionName, ConstraintNam
     LiaisonStatementState, LiaisonStatementTagName, MeetingTypeName, NomineePositionStateName,
     ReviewAssignmentStateName, ReviewRequestStateName, ReviewResultName, ReviewTypeName,
     RoleName, RoomResourceName, SessionStatusName, StdLevelName, StreamName, TimeSlotTypeName,
-    TopicAudienceName, ReviewerQueuePolicyName, TimerangeName, ExtResourceTypeName, ExtResourceName)
+    TopicAudienceName, ReviewerQueuePolicyName, TimerangeName, ExtResourceTypeName, ExtResourceName,
+    SlideSubmissionStatusName)
 
 class TimeSlotTypeNameResource(ModelResource):
     class Meta:
@@ -650,3 +651,20 @@ class ExtResourceNameResource(ModelResource):
             "type": ALL_WITH_RELATIONS,
         }
 api.name.register(ExtResourceNameResource())
+
+class SlideSubmissionStatusNameResource(ModelResource):
+    class Meta:
+        queryset = SlideSubmissionStatusName.objects.all()
+        serializer = api.Serializer()
+        cache = SimpleCache()
+        resource_name = 'slidesubmissionstatusname'
+        ordering = ['slug', ]
+        filtering = { 
+            "slug": ALL,
+            "name": ALL,
+            "desc": ALL,
+            "used": ALL,
+            "order": ALL,
+        }
+api.name.register(SlideSubmissionStatusNameResource())
+
diff --git a/ietf/templates/meeting/previously_approved_slides.html b/ietf/templates/meeting/previously_approved_slides.html
new file mode 100644
index 000000000..a27890288
--- /dev/null
+++ b/ietf/templates/meeting/previously_approved_slides.html
@@ -0,0 +1,20 @@
+{% extends "base.html" %}
+{# Copyright The IETF Trust 2020, All Rights Reserved #}
+{% load origin staticfiles bootstrap3 %}
+
+{% block title %}Approved Slides for {{ submission.session.meeting }} : {{ submission.session.group.acronym }}{% endblock %}
+
+{% block content %}
+  {% origin %}
+
+  <h1>These slides have already been {% if submission.status.slug == 'approved' %} approved {% else %} rejected {% endif %}</h1>
+
+  <p>The slides from {{ submission.submitter }} have already been {% if submission.status.slug == 'approved' %} approved {% else %} rejected {% endif %}.  No further action is needed.</p>
+
+  <p>You may wish to
+    {% if submission.status.slug == 'approved' and submission.doc %}
+    <a href="{% url 'ietf.doc.views_doc.document_main' name=submission.doc.name %}">view the slides</a> or
+    {% endif %}
+    <a href="{% url "ietf.meeting.views.session_details" num=submission.session.meeting.number acronym=submission.session.group.acronym %}">return to this meeting session</a>.</p>
+
+{% endblock %}